Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: hyperium/tonic
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v0.8.3
Choose a base ref
...
head repository: hyperium/tonic
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v0.9.0
Choose a head ref

Commits on Nov 29, 2022

  1. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    8318e75 View commit details
  2. Verified

    This commit was signed with the committer’s verified signature.
    darinpope Darin Pope
    Copy the full SHA
    076a81c View commit details
  3. Copy the full SHA
    c7476ff View commit details
  4. Copy the full SHA
    d6f0567 View commit details

Commits on Nov 30, 2022

  1. Copy the full SHA
    5c8a5d7 View commit details
  2. Copy the full SHA
    95e8c8b View commit details

Commits on Dec 1, 2022

  1. Copy the full SHA
    f7499c8 View commit details
  2. feat(types): Add gRPC Richer Error Model support (RetryInfo) (#1095)

    Add the code related to richer error model support to a new
    `richer_error` module. This improves readability and hopefully will
    make it easier to add new features to `tonic-types` in the future.
    flemosr authored Dec 1, 2022
    Copy the full SHA
    6cdb3d4 View commit details
  3. Copy the full SHA
    1efabf0 View commit details

Commits on Dec 5, 2022

  1. Copy the full SHA
    df8dd89 View commit details

Commits on Dec 6, 2022

  1. Copy the full SHA
    d00fd08 View commit details

Commits on Dec 12, 2022

  1. Copy the full SHA
    3076e82 View commit details

Commits on Dec 13, 2022

  1. Copy the full SHA
    2dd09c0 View commit details
  2. Copy the full SHA
    363c04a View commit details
  3. Copy the full SHA
    35c4946 View commit details
  4. Copy the full SHA
    25ea473 View commit details
  5. Copy the full SHA
    bf22a74 View commit details

Commits on Dec 14, 2022

  1. Copy the full SHA
    4e5c0b2 View commit details

Commits on Dec 15, 2022

  1. Copy the full SHA
    73fdefb View commit details
  2. Copy the full SHA
    797efb2 View commit details
  3. Copy the full SHA
    77fd2a5 View commit details
  4. Copy the full SHA
    c3e5044 View commit details

Commits on Dec 16, 2022

  1. Copy the full SHA
    a457eb5 View commit details
  2. Copy the full SHA
    a8f7e49 View commit details

Commits on Dec 19, 2022

  1. Copy the full SHA
    d9578d7 View commit details
  2. Copy the full SHA
    3ee028d View commit details

Commits on Dec 20, 2022

  1. Copy the full SHA
    b45c5b5 View commit details
  2. Copy the full SHA
    204e8d0 View commit details
  3. Copy the full SHA
    a72cf04 View commit details

Commits on Dec 21, 2022

  1. Copy the full SHA
    a562a3c View commit details

Commits on Dec 22, 2022

  1. Copy the full SHA
    fdff111 View commit details
  2. Copy the full SHA
    cc42d1f View commit details

Commits on Jan 4, 2023

  1. chore: Refactor bootstrap test (#1216)

    * chore: Remove unnecessary conversions to string in bootstrap tests
    
    * chore: Simplify assertion in bootstrap tests
    tottoto authored Jan 4, 2023
    Copy the full SHA
    c772a78 View commit details
  2. Copy the full SHA
    3ee1e6c View commit details
  3. chore: Fix doc warning (#1214)

    * chore(docs): Fix lint warning
    
    * chore: Add ci to check cargo doc
    tottoto authored Jan 4, 2023
    Copy the full SHA
    2d7e14f View commit details
  4. Copy the full SHA
    03b4735 View commit details

Commits on Jan 5, 2023

  1. Copy the full SHA
    b7dffac View commit details
  2. chore(reflection): Add file descriptor set generation (#1213)

    Co-authored-by: Lucio Franco <luciofranco14@gmail.com>
    tottoto and LucioFranco authored Jan 5, 2023
    Copy the full SHA
    b6d9fd6 View commit details

Commits on Jan 6, 2023

  1. Copy the full SHA
    2ec0f87 View commit details
  2. tonic: set a conn timeout for balanced connections (#1215)

    The `endpoint` supplied has a connection_timeout parameter which was
    being ignored in this case.
    ThomWright authored Jan 6, 2023
    Copy the full SHA
    0ca0630 View commit details

Commits on Jan 9, 2023

  1. Copy the full SHA
    1bef5f5 View commit details
  2. Copy the full SHA
    0d35d7f View commit details

Commits on Jan 10, 2023

  1. Copy the full SHA
    d2542dc View commit details
  2. Copy the full SHA
    e326a91 View commit details
  3. Copy the full SHA
    8828e03 View commit details
  4. Copy the full SHA
    54c37a7 View commit details

Commits on Jan 11, 2023

  1. Copy the full SHA
    ee6ccfb View commit details
  2. Copy the full SHA
    63f2e95 View commit details
  3. Copy the full SHA
    e2b1e60 View commit details

Commits on Jan 17, 2023

  1. chore(interop): Lock clap version to 4.0 (#1240)

    * chore(interop): Lock clap version to 4.0
    
    * chore(interop): Lock clap_lex to 0.3.0
    tottoto authored Jan 17, 2023
    Copy the full SHA
    4c69157 View commit details
Showing with 6,127 additions and 1,473 deletions.
  1. +63 −22 .github/workflows/CI.yml
  2. +59 −0 CHANGELOG.md
  3. +18 −0 CONTRIBUTING.md
  4. +2 −0 Cargo.toml
  5. +1 −1 README.md
  6. +8 −8 deny.toml
  7. +124 −46 examples/Cargo.toml
  8. +30 −0 examples/README.md
  9. +2 −0 examples/build.rs
  10. +1 −1 examples/helloworld-tutorial.md
  11. +37 −0 examples/proto/unaryecho/echo.proto
  12. +1 −1 examples/src/authentication/client.rs
  13. +2 −30 examples/src/authentication/server.rs
  14. +1 −1 examples/src/blocking/client.rs
  15. +6 −5 examples/src/{helloworld/server_blocking.rs → blocking/server.rs}
  16. +1 −1 examples/src/dynamic_load_balance/client.rs
  17. +2 −30 examples/src/dynamic_load_balance/server.rs
  18. +3 −2 examples/src/gcp/client.rs
  19. +6 −23 examples/src/grpc-web/client.rs
  20. +2 −3 examples/src/grpc-web/server.rs
  21. +1 −1 examples/src/hyper_warp_multiplex/client.rs
  22. +1 −29 examples/src/hyper_warp_multiplex/server.rs
  23. +1 −1 examples/src/load_balance/client.rs
  24. +2 −30 examples/src/load_balance/server.rs
  25. +0 −1 examples/src/mock/mock.rs
  26. +1 −1 examples/src/multiplex/client.rs
  27. +1 −30 examples/src/multiplex/server.rs
  28. +52 −0 examples/src/richer-error/client.rs
  29. +58 −0 examples/src/richer-error/client_vec.rs
  30. +71 −0 examples/src/richer-error/server.rs
  31. +71 −0 examples/src/richer-error/server_vec.rs
  32. +2 −1 examples/src/routeguide/data.rs
  33. +2 −2 examples/src/streaming/client.rs
  34. +3 −2 examples/src/tls/client.rs
  35. +5 −32 examples/src/tls/server.rs
  36. +5 −4 examples/src/tls_client_auth/client.rs
  37. +5 −32 examples/src/tls_client_auth/server.rs
  38. +5 −2 examples/src/{tls/client_rustls.rs → tls_rustls/client.rs}
  39. +7 −33 examples/src/{tls/server_rustls.rs → tls_rustls/server.rs}
  40. +1 −2 examples/src/tracing/client.rs
  41. +0 −1 examples/src/uds/client.rs
  42. +1 −1 examples/src/uds/server.rs
  43. +8 −6 interop/Cargo.toml
  44. +18 −16 interop/src/bin/client.rs
  45. +13 −6 interop/src/bin/server.rs
  46. +3 −3 interop/src/lib.rs
  47. +1 −1 rustfmt.toml
  48. +4 −1 tests/ambiguous_methods/Cargo.toml
  49. +5 −3 tests/compression/Cargo.toml
  50. +0 −1 tests/compression/src/lib.rs
  51. +5 −2 tests/disable_comments/Cargo.toml
  52. +1 −1 tests/disable_comments/build.rs
  53. +4 −2 tests/extern_path/my_application/Cargo.toml
  54. +5 −3 tests/extern_path/uuid/Cargo.toml
  55. +4 −1 tests/included_service/Cargo.toml
  56. +7 −3 tests/integration_tests/Cargo.toml
  57. +11 −0 tests/integration_tests/proto/test.proto
  58. +6 −0 tests/integration_tests/src/lib.rs
  59. +2 −2 tests/integration_tests/tests/connect_info.rs
  60. +53 −0 tests/integration_tests/tests/interceptor.rs
  61. +278 −0 tests/integration_tests/tests/max_message_size.rs
  62. +0 −1 tests/integration_tests/tests/status.rs
  63. +1 −1 tests/integration_tests/tests/streams.rs
  64. +1 −1 tests/root-crate-path/Cargo.toml
  65. +1 −0 tests/root-crate-path/src/main.rs
  66. +4 −1 tests/same_name/Cargo.toml
  67. +17 −0 tests/service_named_result/Cargo.toml
  68. +19 −0 tests/service_named_result/LICENSE
  69. +3 −0 tests/service_named_result/build.rs
  70. +13 −0 tests/service_named_result/proto/result.proto
  71. +3 −0 tests/service_named_result/src/lib.rs
  72. +4 −1 tests/service_named_service/Cargo.toml
  73. +4 −1 tests/stream_conflict/Cargo.toml
  74. +5 −2 tests/wellknown-compiled/Cargo.toml
  75. +4 −1 tests/wellknown/Cargo.toml
  76. +4 −4 tonic-build/Cargo.toml
  77. +99 −57 tonic-build/src/client.rs
  78. +3 −3 tonic-build/src/code_gen.rs
  79. +29 −3 tonic-build/src/lib.rs
  80. +3 −3 tonic-build/src/manual.rs
  81. +48 −3 tonic-build/src/prost.rs
  82. +76 −53 tonic-build/src/server.rs
  83. +5 −5 tonic-health/Cargo.toml
  84. +85 −11 tonic-health/src/generated/grpc.health.v1.rs
  85. +20 −9 tonic-health/src/lib.rs
  86. +8 −8 tonic-health/src/server.rs
  87. +4 −5 tonic-health/tests/bootstrap.rs
  88. +6 −7 tonic-reflection/Cargo.toml
  89. +75 −7 tonic-reflection/src/generated/grpc.reflection.v1alpha.rs
  90. +15 −2 tonic-reflection/src/lib.rs
  91. +12 −8 tonic-reflection/src/server.rs
  92. +4 −5 tonic-reflection/tests/bootstrap.rs
  93. +1 −1 tonic-reflection/tests/server.rs
  94. +10 −7 tonic-types/Cargo.toml
  95. +145 −0 tonic-types/README.md
  96. +0 −149 tonic-types/src/error_details.rs
  97. +0 −16 tonic-types/src/error_details/vec.rs
  98. 0 tonic-types/src/generated/google.protobuf.rs
  99. +15 −0 tonic-types/src/generated/google.rpc.rs
  100. BIN tonic-types/src/generated/types.bin
  101. +152 −435 tonic-types/src/lib.rs
  102. +882 −0 tonic-types/src/richer_error/error_details/mod.rs
  103. +100 −0 tonic-types/src/richer_error/error_details/vec.rs
  104. +931 −0 tonic-types/src/richer_error/mod.rs
  105. +6 −5 tonic-types/src/{ → richer_error}/std_messages/bad_request.rs
  106. +110 −0 tonic-types/src/richer_error/std_messages/debug_info.rs
  107. +131 −0 tonic-types/src/richer_error/std_messages/error_info.rs
  108. +180 −0 tonic-types/src/richer_error/std_messages/help.rs
  109. +113 −0 tonic-types/src/richer_error/std_messages/loc_message.rs
  110. +39 −0 tonic-types/src/richer_error/std_messages/mod.rs
  111. +205 −0 tonic-types/src/richer_error/std_messages/prec_failure.rs
  112. +182 −0 tonic-types/src/richer_error/std_messages/quota_failure.rs
  113. +112 −0 tonic-types/src/richer_error/std_messages/request_info.rs
  114. +128 −0 tonic-types/src/richer_error/std_messages/resource_info.rs
  115. +148 −0 tonic-types/src/richer_error/std_messages/retry_info.rs
  116. +0 −3 tonic-types/src/std_messages.rs
  117. +6 −5 tonic-types/tests/bootstrap.rs
  118. +7 −7 tonic-web/Cargo.toml
  119. +3 −2 tonic-web/README.md
  120. +5 −3 tonic-web/src/call.rs
  121. +7 −1 tonic-web/src/layer.rs
  122. +81 −15 tonic-web/src/lib.rs
  123. +4 −2 tonic-web/src/service.rs
  124. +2 −2 tonic-web/tests/integration/Cargo.toml
  125. +19 −0 tonic-web/tests/integration/src/lib.rs
  126. +8 −2 tonic-web/tests/integration/tests/grpc_web.rs
  127. +21 −27 tonic/Cargo.toml
  128. +2 −2 tonic/benches-disabled/benchmarks/compiled_protos/helloworld.rs
  129. +1 −1 tonic/benches/decode.rs
  130. +0 −2 tonic/src/body.rs
  131. +95 −4 tonic/src/client/grpc.rs
  132. +45 −6 tonic/src/codec/decode.rs
  133. +28 −3 tonic/src/codec/encode.rs
  134. +4 −0 tonic/src/codec/mod.rs
  135. +73 −4 tonic/src/codec/prost.rs
  136. +3 −9 tonic/src/codegen.rs
  137. +24 −0 tonic/src/extensions.rs
  138. +10 −2 tonic/src/lib.rs
  139. +6 −4 tonic/src/metadata/encoding.rs
  140. +29 −2 tonic/src/metadata/key.rs
  141. +31 −31 tonic/src/metadata/map.rs
  142. +4 −10 tonic/src/metadata/value.rs
  143. +34 −0 tonic/src/request.rs
  144. +4 −2 tonic/src/response.rs
  145. +116 −6 tonic/src/server/grpc.rs
  146. +3 −4 tonic/src/service/interceptor.rs
  147. +40 −11 tonic/src/status.rs
  148. +1 −8 tonic/src/transport/channel/endpoint.rs
  149. +0 −4 tonic/src/transport/channel/tls.rs
  150. +0 −5 tonic/src/transport/error.rs
  151. +4 −2 tonic/src/transport/mod.rs
  152. +8 −0 tonic/src/transport/server/conn.rs
  153. +1 −1 tonic/src/transport/server/incoming.rs
  154. +20 −5 tonic/src/transport/server/tls.rs
  155. +0 −2 tonic/src/transport/service/connector.rs
  156. +1 −0 tonic/src/transport/service/discover.rs
  157. +2 −2 tonic/src/transport/service/io.rs
  158. +1 −1 tonic/src/transport/service/router.rs
  159. +93 −26 tonic/src/transport/service/tls.rs
  160. +24 −0 tonic/src/util.rs
85 changes: 63 additions & 22 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
@@ -18,32 +18,75 @@ jobs:
RUSTFLAGS: "-D warnings"

steps:
- uses: hecrj/setup-rust-action@master
- uses: hecrj/setup-rust-action@v1
with:
rust-version: ${{ matrix.rust }}
- uses: actions/checkout@master
- name: Install rustfmt
run: rustup component add rustfmt
components: rustfmt
- uses: actions/checkout@v3
- name: Install cargo-hack
run: cargo install cargo-hack
uses: baptiste0928/cargo-install@v1
with:
crate: cargo-hack
- name: Install cargo-machete
uses: baptiste0928/cargo-install@v1
with:
crate: cargo-machete
- name: Install Protoc
uses: arduino/setup-protoc@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- uses: Swatinem/rust-cache@v1
- uses: Swatinem/rust-cache@v2
- name: Check fmt
run: cargo fmt -- --check
- name: Check unused dependencies
run: cargo machete
- name: Check features
run: cargo hack check --all --ignore-private --each-feature --no-dev-deps
- name: Check all targets
run: cargo check --all --all-targets --all-features

# deny-check:
# name: cargo-deny check
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v1
# - uses: EmbarkStudios/cargo-deny-action@v1
check-docs:
name: check docs
runs-on: ubuntu-latest

env:
RUSTFLAGS: "-D warnings"

steps:
- uses: actions/checkout@v3
- name: Install Protoc
uses: arduino/setup-protoc@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- uses: hecrj/setup-rust-action@v1
with:
rust-version: "1.60"
- uses: Swatinem/rust-cache@v2
- name: cargo doc
run: cargo doc --workspace --no-deps --exclude examples

deny-check:
name: cargo-deny check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: EmbarkStudios/cargo-deny-action@v1

msrv:
name: Check MSRV
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- uses: hecrj/setup-rust-action@v1
with:
rust-version: "1.60"
- name: Install Protoc
uses: arduino/setup-protoc@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Check
run: cargo check --all --all-targets --all-features

test:
runs-on: ${{ matrix.os }}
@@ -58,17 +101,16 @@ jobs:
QUICKCHECK_TESTS: 1000

steps:
- uses: hecrj/setup-rust-action@master
- uses: hecrj/setup-rust-action@v1
with:
rust-version: ${{ matrix.rust }}
- name: Install rustfmt
run: rustup component add rustfmt
components: rustfmt
- name: Install Protoc
uses: arduino/setup-protoc@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- uses: Swatinem/rust-cache@v1
- uses: actions/checkout@master
- uses: Swatinem/rust-cache@v2
- uses: actions/checkout@v3
- name: Run tests
run: cargo test --all --all-features

@@ -84,17 +126,16 @@ jobs:
RUSTFLAGS: "-D warnings"

steps:
- uses: hecrj/setup-rust-action@master
- uses: hecrj/setup-rust-action@v1
with:
rust-version: ${{ matrix.rust }}
- name: Install rustfmt
run: rustup component add rustfmt
- uses: actions/checkout@master
components: rustfmt
- uses: actions/checkout@v3
- name: Install Protoc
uses: arduino/setup-protoc@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- uses: Swatinem/rust-cache@v1
- uses: Swatinem/rust-cache@v2
- name: Run interop tests
run: ./interop/test.sh
shell: bash
59 changes: 59 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,64 @@
# [v0.9.0](https://github.com/hyperium/tonic/compare/v0.8.4...v0.9.0) (2023-03-31)

All tonic-* crates owned by this repository will now be versioned together to
make it easier to understand which crate matches the core tonic crate version.

### Breaking Changes

- All crates bumped to 2021 edition
- `tonic-health` and `tonic-reflection` internal protobuf module renamed.
- Default decoding message limit set to `4MiB` by default.


### Bug Fixes

* **build:** Allow Services to be named Result ([#1203](https://github.com/hyperium/tonic/issues/1203)) ([a562a3c](https://github.com/hyperium/tonic/commit/a562a3ce329a38696dfcb0d82b7102d93fb30a5c)), closes [#1156](https://github.com/hyperium/tonic/issues/1156)
* **codec:** Cancelled client streaming handling ([#1315](https://github.com/hyperium/tonic/issues/1315)) ([c8027a1](https://github.com/hyperium/tonic/commit/c8027a1385dd5d3fb6abdce7be49c46a43d4f3c2)), closes [#848](https://github.com/hyperium/tonic/issues/848)
* MetadataKey::from_bytes returns an error ([#1246](https://github.com/hyperium/tonic/issues/1246)) ([930c805](https://github.com/hyperium/tonic/commit/930c805127cada70e4e4ab03c7680214b5c2a4f5))
* **web:** Fix `enable` and update docs ([#1326](https://github.com/hyperium/tonic/issues/1326)) ([a9db219](https://github.com/hyperium/tonic/commit/a9db219e50b7d27e48cd44e76941113a36b72e26))


### Features

* add GrpcMethod extension into request for client ([#1275](https://github.com/hyperium/tonic/issues/1275)) ([7a6b20d](https://github.com/hyperium/tonic/commit/7a6b20d8ef5d31c9cc01f0cf697df1f3e28cb421))
* **build:** Builder: add {enum,message}_attributes ([#1234](https://github.com/hyperium/tonic/issues/1234)) ([ff642f9](https://github.com/hyperium/tonic/commit/ff642f9233beab322333745f9edfa9c62ae18ca4))
* **codec:** Configure max request message size ([#1274](https://github.com/hyperium/tonic/issues/1274)) ([9f716d8](https://github.com/hyperium/tonic/commit/9f716d841184b8521720c6ed941af137ca2ee6a0)), closes [#1097](https://github.com/hyperium/tonic/issues/1097)
* **core:** Default encoding/decoding limits ([#1335](https://github.com/hyperium/tonic/issues/1335)) ([ff33119](https://github.com/hyperium/tonic/commit/ff331199e45c8b53e93f1bd51ccd74dafc2146ac))
* **reflection:** Add dummy implementation for extension ([#1209](https://github.com/hyperium/tonic/issues/1209)) ([fdff111](https://github.com/hyperium/tonic/commit/fdff11115b44c4cc7e3de59ea045a193fa6881bc))
* Rename api related to protobuf ([#1224](https://github.com/hyperium/tonic/issues/1224)) ([d2542dc](https://github.com/hyperium/tonic/commit/d2542dc034e89383bd182a25a0d3235859fb10f9))
* **tls:** add an option for optional TLS client authentication ([#1163](https://github.com/hyperium/tonic/issues/1163)) ([773e4e1](https://github.com/hyperium/tonic/commit/773e4e1749daf023222f2294816b1f09d9e916a0)), closes [#687](https://github.com/hyperium/tonic/issues/687)
* **tonic:** Use NamedService without transport feature ([#1273](https://github.com/hyperium/tonic/issues/1273)) ([5acde56](https://github.com/hyperium/tonic/commit/5acde56176d928ffddbf1076e922764fb151f959))
* **transport:** Add `local_addr` to `Request o` ([#1327](https://github.com/hyperium/tonic/issues/1327)) ([b54ce23](https://github.com/hyperium/tonic/commit/b54ce2321a5cba1c32261f4eda2b27d1110b893d))
* **transport:** added support for EC keys ([#1145](https://github.com/hyperium/tonic/issues/1145)) ([17d6a4b](https://github.com/hyperium/tonic/commit/17d6a4b576c1571bb149d3e935e9a835265a80dd)), closes [#1143](https://github.com/hyperium/tonic/issues/1143)
* **types:** Add gRPC Richer Error Model support (Docs) ([#1317](https://github.com/hyperium/tonic/issues/1317)) ([69ce71e](https://github.com/hyperium/tonic/commit/69ce71efa6f4601c9e8060e87d0641a51251e9ab))
* **types:** Add gRPC Richer Error Model support (Examples) ([#1300](https://github.com/hyperium/tonic/issues/1300)) ([d471212](https://github.com/hyperium/tonic/commit/d471212ee8264ca6c5169a9893f361187e9378c9))
* **types:** Add gRPC Richer Error Model support (Help) ([#1293](https://github.com/hyperium/tonic/issues/1293)) ([d6041a9](https://github.com/hyperium/tonic/commit/d6041a99c2a216a2ebc83b7bc5a0947ba7ca869c))
* **types:** Add gRPC Richer Error Model support (LocalizedMessage) ([#1295](https://github.com/hyperium/tonic/issues/1295)) ([d54d02d](https://github.com/hyperium/tonic/commit/d54d02d3ed8bf221c0c54494b7ce692d412391a4))
* **types:** Add gRPC Richer Error Model support (PreconditionFailure) ([#1276](https://github.com/hyperium/tonic/issues/1276)) ([2378581](https://github.com/hyperium/tonic/commit/2378581850483f26fd7c1dee0a797d936b73e881))
* **types:** Add gRPC Richer Error Model support (QuotaFailure) ([#1204](https://github.com/hyperium/tonic/issues/1204)) ([03b4735](https://github.com/hyperium/tonic/commit/03b4735bb4ba7c6e84842d0515d1fd3be9d1cc13))
* **types:** Add gRPC Richer Error Model support (ResourceInfo) ([#1282](https://github.com/hyperium/tonic/issues/1282)) ([7eeda24](https://github.com/hyperium/tonic/commit/7eeda24350c5a61cae7c8e56cc0439d9c40cc77d))
* **types:** Add gRPC Richer Error Model support (RetryInfo) ([#1095](https://github.com/hyperium/tonic/issues/1095)) ([6cdb3d4](https://github.com/hyperium/tonic/commit/6cdb3d4685966b71f051e4cd67c50e1d2db402f5))
* **types:** add support for `DebugInfo` error message type ([#1179](https://github.com/hyperium/tonic/issues/1179)) ([3076e82](https://github.com/hyperium/tonic/commit/3076e8251e602ed6e98a8b3029070b33e3459109))
* **types:** Expose FILE_DESCRIPTOR_SET ([#1210](https://github.com/hyperium/tonic/issues/1210)) ([cc42d1f](https://github.com/hyperium/tonic/commit/cc42d1f88c39d87b244f863daf4ff625f6ff36df))
* **core:** Make some functionality of Status public ([#1256](https://github.com/hyperium/tonic/issues/1256))
* **core:** Expose Response#into_parts and Response#from_parts ([#1263](https://github.com/hyperium/tonic/issues/1263))
* **build:** Allow setting skip_protoc_run on the prost Builder ([#1318](https://github.com/hyperium/tonic/issues/1318))


# [v0.8.4](https://github.com/hyperium/tonic/compare/v0.8.3...v0.8.4) (2022-11-29)

This release only contains a release for `tonic-build`.

### Bug Fixes

* **build:** Fix CodeGen8uilder typo ([#1165](https://github.com/hyperium/tonic/issues/1165)) ([#1166](https://github.com/hyperium/tonic/issues/1166)) ([c7476ff](https://github.com/hyperium/tonic/commit/c7476fff425b972c7966228fd38a9191e8d2ddc9))


# [v0.8.3](https://github.com/hyperium/tonic/compare/v0.8.2...v0.8.3) (2022-11-28)

**note:** this version has been yanked due to a typo in the `CodeGenBuilder`
type.

Included in this release is also the sub-crate major version bumps:

* `tonic-health` has been bumped to `0.8.0`
18 changes: 18 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -206,6 +206,24 @@ example would explicitly use `Timeout::new`. For example:
/// # }
```

#### Generated code

When making changes to `tonic-build` that affects the generated code you will
need to ensure that each of the sub crates gets updated as well. Each of the sub
crates like, for example `tonic-health`, generate their gRPC code via a
`bootstrap.rs` test.

The bootstrap tests work by generating the code and then checking git if there
is any uncommitted generated code (there is a difference between the proto files
and the committed generated code). At this point the test will fail telling you
to commit the new code. When the new code is committed, running the test suite
again will cause it to pass as the generated code doesn't create a diff for git
and thus its up to date.

```
cargo test --all
```

### Commits

It is a recommended best practice to keep your changes as logically grouped as
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -22,4 +22,6 @@ members = [
"tests/root-crate-path",
"tests/compression",
"tonic-web/tests/integration",
"tests/service_named_result",
]
resolver = "2"
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -45,7 +45,7 @@ For IntelliJ IDEA users, please refer to [this](https://github.com/intellij-rust

### Rust Version

`tonic` currently works on Rust `1.56` and above as it requires support for the 2018 edition.
`tonic`'s MSRV is `1.60`.

```bash
$ rustup update
16 changes: 8 additions & 8 deletions deny.toml
Original file line number Diff line number Diff line change
@@ -14,27 +14,27 @@ deny = [
# term is not fully maintained, and termcolor is replacing it
{ name = "term" },
]
skip-tree = [
{ name = "winapi", version = "<= 0.3" },
{ name = "autocfg", version = "<= 1" },
{ name = "version_check", version = "<= 0.9" },
{ name = "scoped-tls", version = ">=0.1" },
{ name = "ansi_term", version = "<= 0.12"},
{ name = "wasi", version = "<= 0.10.0"},
skip-tree = [
{ name = "rustls-pemfile" },
{ name = "windows-sys" },
{ name = "hermit-abi" },
{ name = "syn" },
]

[licenses]
unlicensed = "deny"
# We want really high confidence when inferring licenses from text
confidence-threshold = 0.92
copyleft = "deny"
allow = [
"Apache-2.0",
"BSD-2-Clause",
"BSD-3-Clause",
"ISC",
"MIT",
"OpenSSL",
"Zlib",
"Unicode-DFS-2016",
"MPL-2.0",
]

[[licenses.clarify]]
170 changes: 124 additions & 46 deletions examples/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
authors = ["Lucio Franco <luciofranco14@gmail.com>"]
edition = "2018"
edition = "2021"
license = "MIT"
name = "examples"
publish = false
@@ -14,17 +14,23 @@ path = "src/helloworld/server.rs"
name = "helloworld-client"
path = "src/helloworld/client.rs"

[[bin]]
name = "blocking-server"
path = "src/blocking/server.rs"

[[bin]]
name = "blocking-client"
path = "src/blocking/client.rs"

[[bin]]
name = "routeguide-server"
path = "src/routeguide/server.rs"
required-features = ["routeguide"]

[[bin]]
name = "routeguide-client"
path = "src/routeguide/client.rs"
required-features = ["routeguide"]

[[bin]]
name = "authentication-client"
@@ -45,50 +51,62 @@ path = "src/load_balance/server.rs"
[[bin]]
name = "dynamic-load-balance-client"
path = "src/dynamic_load_balance/client.rs"
required-features = ["dynamic-load-balance"]

[[bin]]
name = "dynamic-load-balance-server"
path = "src/dynamic_load_balance/server.rs"
required-features = ["dynamic-load-balance"]

[[bin]]
name = "tls-client"
path = "src/tls/client.rs"

[[bin]]
name = "tls-client-rustls"
path = "src/tls/client_rustls.rs"
required-features = ["tls"]

[[bin]]
name = "tls-server"
path = "src/tls/server.rs"
required-features = ["tls"]

[[bin]]
name = "tls-server-rustls"
path = "src/tls/server_rustls.rs"
name = "tls-rustls-client"
path = "src/tls_rustls/client.rs"
required-features = ["tls-rustls"]

[[bin]]
name = "tls-rustls-server"
path = "src/tls_rustls/server.rs"
required-features = ["tls-rustls"]

[[bin]]
name = "tls-client-auth-server"
path = "src/tls_client_auth/server.rs"
required-features = ["tls-client-auth"]

[[bin]]
name = "tls-client-auth-client"
path = "src/tls_client_auth/client.rs"
required-features = ["tls-client-auth"]

[[bin]]
name = "tower-server"
path = "src/tower/server.rs"
required-features = ["tower"]

[[bin]]
name = "tower-client"
path = "src/tower/client.rs"
required-features = ["tower"]

[[bin]]
name = "timeout-server"
path = "src/timeout/server.rs"
required-features = ["timeout"]

[[bin]]
name = "timeout-client"
path = "src/timeout/client.rs"
required-features = ["timeout"]

[[bin]]
name = "multiplex-server"
@@ -101,22 +119,27 @@ path = "src/multiplex/client.rs"
[[bin]]
name = "gcp-client"
path = "src/gcp/client.rs"
required-features = ["gcp"]

[[bin]]
name = "tracing-client"
path = "src/tracing/client.rs"
required-features = ["tracing"]

[[bin]]
name = "tracing-server"
path = "src/tracing/server.rs"
required-features = ["tracing"]

[[bin]]
name = "uds-client"
path = "src/uds/client.rs"
required-features = ["uds"]

[[bin]]
name = "uds-server"
path = "src/uds/server.rs"
required-features = ["uds"]

[[bin]]
name = "interceptor-client"
@@ -129,22 +152,27 @@ path = "src/interceptor/server.rs"
[[bin]]
name = "hyper-warp-client"
path = "src/hyper_warp/client.rs"
required-features = ["hyper-warp"]

[[bin]]
name = "hyper-warp-server"
path = "src/hyper_warp/server.rs"
required-features = ["hyper-warp"]

[[bin]]
name = "health-server"
path = "src/health/server.rs"
required-features = ["health"]

[[bin]]
name = "reflection-server"
path = "src/reflection/server.rs"
required-features = ["reflection"]

[[bin]]
name = "autoreload-server"
path = "src/autoreload/server.rs"
required-features = ["autoreload"]

[[bin]]
name = "optional-server"
@@ -153,88 +181,138 @@ path = "src/optional/server.rs"
[[bin]]
name = "hyper-warp-multiplex-client"
path = "src/hyper_warp_multiplex/client.rs"
required-features = ["hyper-warp-multiplex"]

[[bin]]
name = "hyper-warp-multiplex-server"
path = "src/hyper_warp_multiplex/server.rs"
required-features = ["hyper-warp-multiplex"]

[[bin]]
name = "compression-server"
path = "src/compression/server.rs"
required-features = ["compression"]

[[bin]]
name = "compression-client"
path = "src/compression/client.rs"
required-features = ["compression"]

[[bin]]
name = "mock"
path = "src/mock/mock.rs"
required-features = ["mock"]

[[bin]]
name = "grpc-web-server"
path = "src/grpc-web/server.rs"
required-features = ["grpc-web"]

[[bin]]
name = "grpc-web-client"
path = "src/grpc-web/client.rs"
required-features = ["grpc-web"]

[[bin]]
name = "streaming-client"
path = "src/streaming/client.rs"
required-features = ["streaming"]

[[bin]]
name = "streaming-server"
path = "src/streaming/server.rs"
required-features = ["streaming"]

[[bin]]
name = "json-codec-client"
path = "src/json-codec/client.rs"
required-features = ["json-codec"]

[[bin]]
name = "json-codec-server"
path = "src/json-codec/server.rs"
required-features = ["json-codec"]

[[bin]]
name = "richer-error-client"
path = "src/richer-error/client.rs"
required-features = ["types"]

[[bin]]
name = "richer-error-server"
path = "src/richer-error/server.rs"
required-features = ["types"]

[[bin]]
name = "richer-error-client-vec"
path = "src/richer-error/client_vec.rs"
required-features = ["types"]

[[bin]]
name = "richer-error-server-vec"
path = "src/richer-error/server_vec.rs"
required-features = ["types"]

[features]
gcp = ["dep:prost-types", "tonic/tls"]
routeguide = ["dep:async-stream", "dep:futures", "tokio-stream", "dep:rand", "dep:serde", "dep:serde_json"]
reflection = ["dep:tonic-reflection"]
autoreload = ["tokio-stream/net", "dep:listenfd"]
health = ["dep:tonic-health"]
grpc-web = ["dep:tonic-web", "dep:bytes", "dep:http", "dep:hyper", "dep:tracing-subscriber"]
tracing = ["dep:tracing", "dep:tracing-subscriber"]
hyper-warp = ["dep:futures", "dep:tower", "dep:hyper", "dep:http", "dep:http-body", "dep:warp"]
hyper-warp-multiplex = ["hyper-warp"]
uds = ["tokio-stream/net", "dep:tower", "dep:hyper"]
streaming = ["dep:futures", "tokio-stream", "dep:h2"]
mock = ["dep:futures", "dep:tower"]
tower = ["dep:futures", "dep:hyper", "dep:tower", "dep:http"]
json-codec = ["dep:serde", "dep:serde_json", "dep:bytes"]
compression = ["tonic/gzip"]
tls = ["tonic/tls"]
tls-rustls = ["dep:hyper", "dep:hyper-rustls", "dep:tower", "tower-http/util", "tower-http/add-extension", "dep:rustls-pemfile", "dep:tokio-rustls"]
dynamic-load-balance = ["dep:tower"]
timeout = ["tokio/time", "dep:tower"]
tls-client-auth = ["tonic/tls"]
types = ["dep:tonic-types"]

full = ["gcp", "routeguide", "reflection", "autoreload", "health", "grpc-web", "tracing", "hyper-warp", "hyper-warp-multiplex", "uds", "streaming", "mock", "tower", "json-codec", "compression", "tls", "tls-rustls", "dynamic-load-balance", "timeout", "tls-client-auth", "types"]
default = ["full"]

[dependencies]
async-stream = "0.3"
futures = { version = "0.3", default-features = false, features = ["alloc"] }
# Common dependencies
tokio = { version = "1.0", features = ["rt-multi-thread", "macros"] }
prost = "0.11"
tokio = { version = "1.0", features = [ "rt-multi-thread", "time", "fs", "macros", "net",] }
tokio-stream = { version = "0.1", features = ["net"] }
tonic = { path = "../tonic", features = ["tls", "gzip"] }
tower = { version = "0.4" }
# Required for routeguide
rand = "0.8"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
# Tracing
tracing = "0.1.16"
tracing-attributes = "0.1"
tracing-futures = "0.2"
tracing-subscriber = { version = "0.3", features = ["tracing-log"] }
# Required for wellknown types
prost-types = "0.11"
# Hyper example
http = "0.2"
http-body = "0.4.2"
hyper = { version = "0.14", features = ["full"] }
pin-project = "1.0"
warp = "0.3"
# Health example
tonic-health = { path = "../tonic-health" }
# Reflection example
listenfd = "0.3"
tonic-reflection = { path = "../tonic-reflection" }
# grpc-web example
bytes = "1"
tonic-web = { path = "../tonic-web" }
# streaming example
h2 = "0.3"

tokio-rustls = "*"
hyper-rustls = { version = "0.23", features = ["http2"] }
rustls-pemfile = "*"
tower-http = { version = "0.3", features = ["add-extension", "util"] }

tonic = { path = "../tonic" }
# Optional dependencies
tonic-web = { path = "../tonic-web", optional = true }
tonic-health = { path = "../tonic-health", optional = true }
tonic-reflection = { path = "../tonic-reflection", optional = true }
tonic-types = { path = "../tonic-types", optional = true }
async-stream = { version = "0.3", optional = true }
futures = { version = "0.3", default-features = false, optional = true }
tokio-stream = { version = "0.1", optional = true }
tower = { version = "0.4", optional = true }
rand = { version = "0.8", optional = true }
serde = { version = "1.0", features = ["derive"], optional = true }
serde_json = { version = "1.0", optional = true }
tracing = { version = "0.1.16", optional = true }
tracing-subscriber = { version = "0.3", features = ["tracing-log", "fmt"], optional = true }
prost-types = { version = "0.11", optional = true }
http = { version = "0.2", optional = true }
http-body = { version = "0.4.2", optional = true }
hyper = { version = "0.14", optional = true }
warp = { version = "0.3", default-features = false, optional = true }
listenfd = { version = "1.0", optional = true }
bytes = { version = "1", optional = true }
h2 = { version = "0.3", optional = true }
tokio-rustls = { version = "0.23", optional = true }
hyper-rustls = { version = "0.23", features = ["http2"], optional = true }
rustls-pemfile = { version = "1", optional = true }
tower-http = { version = "0.4", optional = true }

[build-dependencies]
tonic-build = { path = "../tonic-build", features = ["prost"] }

[package.metadata.cargo-machete]
ignored = ["prost-types"]
30 changes: 30 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -153,3 +153,33 @@ The autoload example requires the following crates installed globally:

* [systemfd](https://crates.io/crates/systemfd)
* [cargo-watch](https://crates.io/crates/cargo-watch)

## Richer Error

Both clients and both servers do the same thing, but using the two different
approaches. Run one of the servers in one terminal, and then run the clients
in another.

### Client using the `ErrorDetails` struct

```bash
$ cargo run --bin richer-error-client
```

### Client using a vector of error message types

```bash
$ cargo run --bin richer-error-client-vec
```

### Server using the `ErrorDetails` struct

```bash
$ cargo run --bin richer-error-server
```

### Server using a vector of error message types

```bash
$ cargo run --bin richer-error-server-vec
```
2 changes: 2 additions & 0 deletions examples/build.rs
Original file line number Diff line number Diff line change
@@ -14,6 +14,8 @@ fn main() {

tonic_build::compile_protos("proto/echo/echo.proto").unwrap();

tonic_build::compile_protos("proto/unaryecho/echo.proto").unwrap();

tonic_build::configure()
.server_mod_attribute("attrs", "#[cfg(feature = \"server\")]")
.server_attribute("Echo", "#[derive(PartialEq)]")
2 changes: 1 addition & 1 deletion examples/helloworld-tutorial.md
Original file line number Diff line number Diff line change
@@ -243,7 +243,7 @@ If you have a gRPC GUI client such as [Bloom RPC] you should be able to send req

Or if you use [grpcurl] then you can simply try send requests like this:
```
$ grpcurl -plaintext -import-path ./proto -proto helloworld.proto -d '{"name": "Tonic"}' '[::]:50051' helloworld.Greeter/SayHello
$ grpcurl -plaintext -import-path ./proto -proto helloworld.proto -d '{"name": "Tonic"}' '[::1]:50051' helloworld.Greeter/SayHello
```
And receiving responses like this:
```
37 changes: 37 additions & 0 deletions examples/proto/unaryecho/echo.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
*
* Copyright 2018 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

syntax = "proto3";

package grpc.examples.unaryecho;

// EchoRequest is the request for echo.
message EchoRequest {
string message = 1;
}

// EchoResponse is the response for echo.
message EchoResponse {
string message = 1;
}

// Echo is the echo service.
service Echo {
// UnaryEcho is unary echo.
rpc UnaryEcho(EchoRequest) returns (EchoResponse) {}
}
2 changes: 1 addition & 1 deletion examples/src/authentication/client.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
pub mod pb {
tonic::include_proto!("grpc.examples.echo");
tonic::include_proto!("grpc.examples.unaryecho");
}

use pb::{echo_client::EchoClient, EchoRequest};
32 changes: 2 additions & 30 deletions examples/src/authentication/server.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
pub mod pb {
tonic::include_proto!("grpc.examples.echo");
tonic::include_proto!("grpc.examples.unaryecho");
}

use futures::Stream;
use pb::{EchoRequest, EchoResponse};
use std::pin::Pin;
use tonic::{metadata::MetadataValue, transport::Server, Request, Response, Status, Streaming};
use tonic::{metadata::MetadataValue, transport::Server, Request, Response, Status};

type EchoResult<T> = Result<Response<T>, Status>;
type ResponseStream = Pin<Box<dyn Stream<Item = Result<EchoResponse, Status>> + Send>>;

#[derive(Default)]
pub struct EchoServer;
@@ -19,31 +16,6 @@ impl pb::echo_server::Echo for EchoServer {
let message = request.into_inner().message;
Ok(Response::new(EchoResponse { message }))
}

type ServerStreamingEchoStream = ResponseStream;

async fn server_streaming_echo(
&self,
_: Request<EchoRequest>,
) -> EchoResult<Self::ServerStreamingEchoStream> {
Err(Status::unimplemented("not implemented"))
}

async fn client_streaming_echo(
&self,
_: Request<Streaming<EchoRequest>>,
) -> EchoResult<EchoResponse> {
Err(Status::unimplemented("not implemented"))
}

type BidirectionalStreamingEchoStream = ResponseStream;

async fn bidirectional_streaming_echo(
&self,
_: Request<Streaming<EchoRequest>>,
) -> EchoResult<Self::BidirectionalStreamingEchoStream> {
Err(Status::unimplemented("not implemented"))
}
}

#[tokio::main]
2 changes: 1 addition & 1 deletion examples/src/blocking/client.rs
Original file line number Diff line number Diff line change
@@ -21,7 +21,7 @@ struct BlockingClient {
impl BlockingClient {
pub fn connect<D>(dst: D) -> Result<Self, tonic::transport::Error>
where
D: std::convert::TryInto<tonic::transport::Endpoint>,
D: TryInto<tonic::transport::Endpoint>,
D::Error: Into<StdError>,
{
let rt = Builder::new_multi_thread().enable_all().build().unwrap();
Original file line number Diff line number Diff line change
@@ -21,7 +21,7 @@ impl Greeter for MyGreeter {
println!("Got a request: {:?}", request);

let reply = hello_world::HelloReply {
message: format!("Hello {}!", request.into_inner().name).into(),
message: format!("Hello {}!", request.into_inner().name),
};

Ok(Response::new(reply))
@@ -32,9 +32,10 @@ fn main() {
let addr = "[::1]:50051".parse().unwrap();
let greeter = MyGreeter::default();

let mut rt = Runtime::new().expect("failed to obtain a new RunTime object");
let rt = Runtime::new().expect("failed to obtain a new RunTime object");
let server_future = Server::builder()
.add_service(GreeterServer::new(greeter))
.serve(addr);
rt.block_on(server_future).expect("failed to successfully run the future on RunTime");
.add_service(GreeterServer::new(greeter))
.serve(addr);
rt.block_on(server_future)
.expect("failed to successfully run the future on RunTime");
}
2 changes: 1 addition & 1 deletion examples/src/dynamic_load_balance/client.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
pub mod pb {
tonic::include_proto!("grpc.examples.echo");
tonic::include_proto!("grpc.examples.unaryecho");
}

use pb::{echo_client::EchoClient, EchoRequest};
32 changes: 2 additions & 30 deletions examples/src/dynamic_load_balance/server.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
pub mod pb {
tonic::include_proto!("grpc.examples.echo");
tonic::include_proto!("grpc.examples.unaryecho");
}

use futures::Stream;
use std::net::SocketAddr;
use std::pin::Pin;
use tokio::sync::mpsc;
use tonic::{transport::Server, Request, Response, Status, Streaming};
use tonic::{transport::Server, Request, Response, Status};

use pb::{EchoRequest, EchoResponse};

type EchoResult<T> = Result<Response<T>, Status>;
type ResponseStream = Pin<Box<dyn Stream<Item = Result<EchoResponse, Status>> + Send>>;

#[derive(Debug)]
pub struct EchoServer {
@@ -25,31 +22,6 @@ impl pb::echo_server::Echo for EchoServer {

Ok(Response::new(EchoResponse { message }))
}

type ServerStreamingEchoStream = ResponseStream;

async fn server_streaming_echo(
&self,
_: Request<EchoRequest>,
) -> EchoResult<Self::ServerStreamingEchoStream> {
Err(Status::unimplemented("not implemented"))
}

async fn client_streaming_echo(
&self,
_: Request<Streaming<EchoRequest>>,
) -> EchoResult<EchoResponse> {
Err(Status::unimplemented("not implemented"))
}

type BidirectionalStreamingEchoStream = ResponseStream;

async fn bidirectional_streaming_echo(
&self,
_: Request<Streaming<EchoRequest>>,
) -> EchoResult<Self::BidirectionalStreamingEchoStream> {
Err(Status::unimplemented("not implemented"))
}
}

#[tokio::main]
5 changes: 3 additions & 2 deletions examples/src/gcp/client.rs
Original file line number Diff line number Diff line change
@@ -24,10 +24,11 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let bearer_token = format!("Bearer {}", token);
let header_value: MetadataValue<_> = bearer_token.parse()?;

let certs = tokio::fs::read("examples/data/gcp/roots.pem").await?;
let data_dir = std::path::PathBuf::from_iter([std::env!("CARGO_MANIFEST_DIR"), "data"]);
let certs = std::fs::read_to_string(data_dir.join("gcp/roots.pem"))?;

let tls_config = ClientTlsConfig::new()
.ca_certificate(Certificate::from_pem(certs.as_slice()))
.ca_certificate(Certificate::from_pem(certs))
.domain_name("pubsub.googleapis.com");

let channel = Channel::from_static(ENDPOINT)
29 changes: 6 additions & 23 deletions examples/src/grpc-web/client.rs
Original file line number Diff line number Diff line change
@@ -46,32 +46,15 @@ fn encode_body<T>(msg: T) -> Bytes
where
T: prost::Message,
{
let mut buf = BytesMut::with_capacity(1024);
let msg_len = msg.encoded_len();
let mut buf = BytesMut::with_capacity(GRPC_HEADER_SIZE + msg_len);

// first skip past the header
// cannot write it yet since we don't know the size of the
// encoded message
buf.reserve(GRPC_HEADER_SIZE);
unsafe {
buf.advance_mut(GRPC_HEADER_SIZE);
}
// compression flag, 0 means "no compression"
buf.put_u8(0);
buf.put_u32(msg_len as u32);

// write the message
msg.encode(&mut buf).unwrap();

// now we know the size of encoded message and can write the
// header
let len = buf.len() - GRPC_HEADER_SIZE;
{
let mut buf = &mut buf[..GRPC_HEADER_SIZE];

// compression flag, 0 means "no compression"
buf.put_u8(0);

buf.put_u32(len as u32);
}

buf.split_to(len + GRPC_HEADER_SIZE).freeze()
buf.freeze()
}

async fn decode_body<T>(body: hyper::Body) -> T
5 changes: 2 additions & 3 deletions examples/src/grpc-web/server.rs
Original file line number Diff line number Diff line change
@@ -2,7 +2,6 @@ use tonic::{transport::Server, Request, Response, Status};

use hello_world::greeter_server::{Greeter, GreeterServer};
use hello_world::{HelloReply, HelloRequest};
use tonic_web::GrpcWebLayer;

pub mod hello_world {
tonic::include_proto!("helloworld");
@@ -38,9 +37,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("GreeterServer listening on {}", addr);

Server::builder()
// GrpcWeb is over http1 so we must enable it.
.accept_http1(true)
.layer(GrpcWebLayer::new())
.add_service(greeter)
.add_service(tonic_web::enable(greeter))
.serve(addr)
.await?;

2 changes: 1 addition & 1 deletion examples/src/hyper_warp_multiplex/client.rs
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@ pub mod hello_world {
}

pub mod echo {
tonic::include_proto!("grpc.examples.echo");
tonic::include_proto!("grpc.examples.unaryecho");
}

use echo::{echo_client::EchoClient, EchoRequest};
30 changes: 1 addition & 29 deletions examples/src/hyper_warp_multiplex/server.rs
Original file line number Diff line number Diff line change
@@ -4,7 +4,6 @@
//! `curl localhost:50051/hello`
use futures::future::{self, Either, TryFutureExt};
use futures::Stream;
use http::version::Version;
use hyper::{service::make_service_fn, Server};
use std::convert::Infallible;
@@ -23,7 +22,7 @@ pub mod hello_world {
}

pub mod echo {
tonic::include_proto!("grpc.examples.echo");
tonic::include_proto!("grpc.examples.unaryecho");
}
use hello_world::{
greeter_server::{Greeter, GreeterServer},
@@ -35,8 +34,6 @@ use echo::{
EchoRequest, EchoResponse,
};

type ResponseStream = Pin<Box<dyn Stream<Item = Result<EchoResponse, Status>> + Send>>;

#[derive(Default)]
pub struct MyGreeter {}

@@ -65,31 +62,6 @@ impl Echo for MyEcho {
let message = request.into_inner().message;
Ok(Response::new(EchoResponse { message }))
}

type ServerStreamingEchoStream = ResponseStream;

async fn server_streaming_echo(
&self,
_: Request<EchoRequest>,
) -> Result<Response<Self::ServerStreamingEchoStream>, Status> {
Err(Status::unimplemented("Not yet implemented"))
}

async fn client_streaming_echo(
&self,
_: Request<tonic::Streaming<EchoRequest>>,
) -> Result<Response<EchoResponse>, Status> {
Err(Status::unimplemented("Not yet implemented"))
}

type BidirectionalStreamingEchoStream = ResponseStream;

async fn bidirectional_streaming_echo(
&self,
_: Request<tonic::Streaming<EchoRequest>>,
) -> Result<Response<Self::BidirectionalStreamingEchoStream>, Status> {
Err(Status::unimplemented("Not yet implemented"))
}
}

#[tokio::main]
2 changes: 1 addition & 1 deletion examples/src/load_balance/client.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
pub mod pb {
tonic::include_proto!("grpc.examples.echo");
tonic::include_proto!("grpc.examples.unaryecho");
}

use pb::{echo_client::EchoClient, EchoRequest};
32 changes: 2 additions & 30 deletions examples/src/load_balance/server.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
pub mod pb {
tonic::include_proto!("grpc.examples.echo");
tonic::include_proto!("grpc.examples.unaryecho");
}

use futures::Stream;
use std::net::SocketAddr;
use std::pin::Pin;
use tokio::sync::mpsc;
use tonic::{transport::Server, Request, Response, Status, Streaming};
use tonic::{transport::Server, Request, Response, Status};

use pb::{EchoRequest, EchoResponse};

type EchoResult<T> = Result<Response<T>, Status>;
type ResponseStream = Pin<Box<dyn Stream<Item = Result<EchoResponse, Status>> + Send>>;

#[derive(Debug)]
pub struct EchoServer {
@@ -25,31 +22,6 @@ impl pb::echo_server::Echo for EchoServer {

Ok(Response::new(EchoResponse { message }))
}

type ServerStreamingEchoStream = ResponseStream;

async fn server_streaming_echo(
&self,
_: Request<EchoRequest>,
) -> EchoResult<Self::ServerStreamingEchoStream> {
Err(Status::unimplemented("not implemented"))
}

async fn client_streaming_echo(
&self,
_: Request<Streaming<EchoRequest>>,
) -> EchoResult<EchoResponse> {
Err(Status::unimplemented("not implemented"))
}

type BidirectionalStreamingEchoStream = ResponseStream;

async fn bidirectional_streaming_echo(
&self,
_: Request<Streaming<EchoRequest>>,
) -> EchoResult<Self::BidirectionalStreamingEchoStream> {
Err(Status::unimplemented("not implemented"))
}
}

#[tokio::main]
1 change: 0 additions & 1 deletion examples/src/mock/mock.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use std::convert::TryFrom;
use tonic::{
transport::{Endpoint, Server, Uri},
Request, Response, Status,
2 changes: 1 addition & 1 deletion examples/src/multiplex/client.rs
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@ pub mod hello_world {
}

pub mod echo {
tonic::include_proto!("grpc.examples.echo");
tonic::include_proto!("grpc.examples.unaryecho");
}

use echo::{echo_client::EchoClient, EchoRequest};
31 changes: 1 addition & 30 deletions examples/src/multiplex/server.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
use futures::Stream;
use std::pin::Pin;
use tonic::{transport::Server, Request, Response, Status};

pub mod hello_world {
tonic::include_proto!("helloworld");
}

pub mod echo {
tonic::include_proto!("grpc.examples.echo");
tonic::include_proto!("grpc.examples.unaryecho");
}

use hello_world::{
@@ -20,8 +18,6 @@ use echo::{
EchoRequest, EchoResponse,
};

type ResponseStream = Pin<Box<dyn Stream<Item = Result<EchoResponse, Status>> + Send>>;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let addr = "[::1]:50051".parse().unwrap();
@@ -66,29 +62,4 @@ impl Echo for MyEcho {
let message = request.into_inner().message;
Ok(Response::new(EchoResponse { message }))
}

type ServerStreamingEchoStream = ResponseStream;

async fn server_streaming_echo(
&self,
_: Request<EchoRequest>,
) -> Result<Response<Self::ServerStreamingEchoStream>, Status> {
Err(Status::unimplemented("Not yet implemented"))
}

async fn client_streaming_echo(
&self,
_: Request<tonic::Streaming<EchoRequest>>,
) -> Result<Response<EchoResponse>, Status> {
Err(Status::unimplemented("Not yet implemented"))
}

type BidirectionalStreamingEchoStream = ResponseStream;

async fn bidirectional_streaming_echo(
&self,
_: Request<tonic::Streaming<EchoRequest>>,
) -> Result<Response<Self::BidirectionalStreamingEchoStream>, Status> {
Err(Status::unimplemented("Not yet implemented"))
}
}
52 changes: 52 additions & 0 deletions examples/src/richer-error/client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
use tonic_types::StatusExt;

use hello_world::greeter_client::GreeterClient;
use hello_world::HelloRequest;

pub mod hello_world {
tonic::include_proto!("helloworld");
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = GreeterClient::connect("http://[::1]:50051").await?;

let request = tonic::Request::new(HelloRequest {
// Valid request
// name: "Tonic".into(),
// Name cannot be empty
name: "".into(),
// Name is too long
// name: "some excessively long name".into(),
});

let response = match client.say_hello(request).await {
Ok(response) => response,
Err(status) => {
println!(" Error status received. Extracting error details...\n");

let err_details = status.get_error_details();

if let Some(bad_request) = err_details.bad_request() {
// Handle bad_request details
println!(" {:?}", bad_request);
}
if let Some(help) = err_details.help() {
// Handle help details
println!(" {:?}", help);
}
if let Some(localized_message) = err_details.localized_message() {
// Handle localized_message details
println!(" {:?}", localized_message);
}

println!();

return Ok(());
}
};

println!(" Successfull response received.\n\n {:?}\n", response);

Ok(())
}
58 changes: 58 additions & 0 deletions examples/src/richer-error/client_vec.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
use tonic_types::{ErrorDetail, StatusExt};

use hello_world::greeter_client::GreeterClient;
use hello_world::HelloRequest;

pub mod hello_world {
tonic::include_proto!("helloworld");
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = GreeterClient::connect("http://[::1]:50051").await?;

let request = tonic::Request::new(HelloRequest {
// Valid request
// name: "Tonic".into(),
// Name cannot be empty
name: "".into(),
// Name is too long
// name: "some excessively long name".into(),
});

let response = match client.say_hello(request).await {
Ok(response) => response,
Err(status) => {
println!(" Error status received. Extracting error details...\n");

let err_details = status.get_error_details_vec();

for (i, err_detail) in err_details.iter().enumerate() {
println!("err_detail[{i}]");
match err_detail {
ErrorDetail::BadRequest(bad_request) => {
// Handle bad_request details
println!(" {:?}", bad_request);
}
ErrorDetail::Help(help) => {
// Handle help details
println!(" {:?}", help);
}
ErrorDetail::LocalizedMessage(localized_message) => {
// Handle localized_message details
println!(" {:?}", localized_message);
}
_ => {}
}
}

println!();

return Ok(());
}
};

println!(" Successfull response received.\n\n {:?}\n", response);

Ok(())
}
71 changes: 71 additions & 0 deletions examples/src/richer-error/server.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
use tonic::{transport::Server, Code, Request, Response, Status};
use tonic_types::{ErrorDetails, StatusExt};

use hello_world::greeter_server::{Greeter, GreeterServer};
use hello_world::{HelloReply, HelloRequest};

pub mod hello_world {
tonic::include_proto!("helloworld");
}

#[derive(Default)]
pub struct MyGreeter {}

#[tonic::async_trait]
impl Greeter for MyGreeter {
async fn say_hello(
&self,
request: Request<HelloRequest>,
) -> Result<Response<HelloReply>, Status> {
println!("Got a request from {:?}", request.remote_addr());

// Extract request data
let name = request.into_inner().name;

// Create empty ErrorDetails struct
let mut err_details = ErrorDetails::new();

// Add error details conditionally
if name.is_empty() {
err_details.add_bad_request_violation("name", "name cannot be empty");
} else if name.len() > 20 {
err_details.add_bad_request_violation("name", "name is too long");
}

if err_details.has_bad_request_violations() {
// Add aditional error details if necessary
err_details
.add_help_link("description of link", "https://resource.example.local")
.set_localized_message("en-US", "message for the user");

// Generate error status
let status = Status::with_error_details(
Code::InvalidArgument,
"request contains invalid arguments",
err_details,
);

return Err(status);
}

let reply = hello_world::HelloReply {
message: format!("Hello {}!", name),
};
Ok(Response::new(reply))
}
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let addr = "[::1]:50051".parse().unwrap();
let greeter = MyGreeter::default();

println!("GreeterServer listening on {}", addr);

Server::builder()
.add_service(GreeterServer::new(greeter))
.serve(addr)
.await?;

Ok(())
}
71 changes: 71 additions & 0 deletions examples/src/richer-error/server_vec.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
use tonic::{transport::Server, Code, Request, Response, Status};
use tonic_types::{BadRequest, Help, LocalizedMessage, StatusExt};

use hello_world::greeter_server::{Greeter, GreeterServer};
use hello_world::{HelloReply, HelloRequest};

pub mod hello_world {
tonic::include_proto!("helloworld");
}

#[derive(Default)]
pub struct MyGreeter {}

#[tonic::async_trait]
impl Greeter for MyGreeter {
async fn say_hello(
&self,
request: Request<HelloRequest>,
) -> Result<Response<HelloReply>, Status> {
println!("Got a request from {:?}", request.remote_addr());

// Extract request data
let name = request.into_inner().name;

// Create empty BadRequest struct
let mut bad_request = BadRequest::new(vec![]);

// Add violations conditionally
if name.is_empty() {
bad_request.add_violation("name", "name cannot be empty");
} else if name.len() > 20 {
bad_request.add_violation("name", "name is too long");
}

if !bad_request.is_empty() {
// Add aditional error details if necessary
let help = Help::with_link("description of link", "https://resource.example.local");

let localized_message = LocalizedMessage::new("en-US", "message for the user");

// Generate error status
let status = Status::with_error_details_vec(
Code::InvalidArgument,
"request contains invalid arguments",
vec![bad_request.into(), help.into(), localized_message.into()],
);

return Err(status);
}

let reply = hello_world::HelloReply {
message: format!("Hello {}!", name),
};
Ok(Response::new(reply))
}
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let addr = "[::1]:50051".parse().unwrap();
let greeter = MyGreeter::default();

println!("GreeterServer listening on {}", addr);

Server::builder()
.add_service(GreeterServer::new(greeter))
.serve(addr)
.await?;

Ok(())
}
3 changes: 2 additions & 1 deletion examples/src/routeguide/data.rs
Original file line number Diff line number Diff line change
@@ -15,7 +15,8 @@ struct Location {

#[allow(dead_code)]
pub fn load() -> Vec<crate::routeguide::Feature> {
let file = File::open("examples/data/route_guide_db.json").expect("failed to open data file");
let data_dir = std::path::PathBuf::from_iter([std::env!("CARGO_MANIFEST_DIR"), "data"]);
let file = File::open(data_dir.join("route_guide_db.json")).expect("failed to open data file");

let decoded: Vec<Feature> =
serde_json::from_reader(&file).expect("failed to deserialize features");
4 changes: 2 additions & 2 deletions examples/src/streaming/client.rs
Original file line number Diff line number Diff line change
@@ -76,9 +76,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("\r\nBidirectional stream echo:");
bidirectional_streaming_echo(&mut client, 17).await;

// Echo stream that sends up to `usize::MAX` requets. One request each 2s.
// Echo stream that sends up to `usize::MAX` requests. One request each 2s.
// Exiting client with CTRL+C demonstrate how to distinguish broken pipe from
//graceful client disconnection (above example) on the server side.
// graceful client disconnection (above example) on the server side.
println!("\r\nBidirectional stream echo (kill client with CTLR+C):");
bidirectional_streaming_echo_throttle(&mut client, Duration::from_secs(2)).await;

5 changes: 3 additions & 2 deletions examples/src/tls/client.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
pub mod pb {
tonic::include_proto!("/grpc.examples.echo");
tonic::include_proto!("/grpc.examples.unaryecho");
}

use pb::{echo_client::EchoClient, EchoRequest};
use tonic::transport::{Certificate, Channel, ClientTlsConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let pem = tokio::fs::read("examples/data/tls/ca.pem").await?;
let data_dir = std::path::PathBuf::from_iter([std::env!("CARGO_MANIFEST_DIR"), "data"]);
let pem = std::fs::read_to_string(data_dir.join("tls/ca.pem"))?;
let ca = Certificate::from_pem(pem);

let tls = ClientTlsConfig::new()
37 changes: 5 additions & 32 deletions examples/src/tls/server.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
pub mod pb {
tonic::include_proto!("/grpc.examples.echo");
tonic::include_proto!("/grpc.examples.unaryecho");
}

use futures::Stream;
use pb::{EchoRequest, EchoResponse};
use std::pin::Pin;
use tonic::{
transport::{
server::{TcpConnectInfo, TlsConnectInfo},
Identity, Server, ServerTlsConfig,
},
Request, Response, Status, Streaming,
Request, Response, Status,
};

type EchoResult<T> = Result<Response<T>, Status>;
type ResponseStream = Pin<Box<dyn Stream<Item = Result<EchoResponse, Status>> + Send>>;

#[derive(Default)]
pub struct EchoServer;
@@ -35,37 +32,13 @@ impl pb::echo_server::Echo for EchoServer {
let message = request.into_inner().message;
Ok(Response::new(EchoResponse { message }))
}

type ServerStreamingEchoStream = ResponseStream;

async fn server_streaming_echo(
&self,
_: Request<EchoRequest>,
) -> EchoResult<Self::ServerStreamingEchoStream> {
Err(Status::unimplemented("not implemented"))
}

async fn client_streaming_echo(
&self,
_: Request<Streaming<EchoRequest>>,
) -> EchoResult<EchoResponse> {
Err(Status::unimplemented("not implemented"))
}

type BidirectionalStreamingEchoStream = ResponseStream;

async fn bidirectional_streaming_echo(
&self,
_: Request<Streaming<EchoRequest>>,
) -> EchoResult<Self::BidirectionalStreamingEchoStream> {
Err(Status::unimplemented("not implemented"))
}
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let cert = tokio::fs::read("examples/data/tls/server.pem").await?;
let key = tokio::fs::read("examples/data/tls/server.key").await?;
let data_dir = std::path::PathBuf::from_iter([std::env!("CARGO_MANIFEST_DIR"), "data"]);
let cert = std::fs::read_to_string(data_dir.join("tls/server.pem"))?;
let key = std::fs::read_to_string(data_dir.join("tls/server.key"))?;

let identity = Identity::from_pem(cert, key);

9 changes: 5 additions & 4 deletions examples/src/tls_client_auth/client.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
pub mod pb {
tonic::include_proto!("grpc.examples.echo");
tonic::include_proto!("grpc.examples.unaryecho");
}

use pb::{echo_client::EchoClient, EchoRequest};
use tonic::transport::{Certificate, Channel, ClientTlsConfig, Identity};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let server_root_ca_cert = tokio::fs::read("examples/data/tls/ca.pem").await?;
let data_dir = std::path::PathBuf::from_iter([std::env!("CARGO_MANIFEST_DIR"), "data"]);
let server_root_ca_cert = std::fs::read_to_string(data_dir.join("tls/ca.pem"))?;
let server_root_ca_cert = Certificate::from_pem(server_root_ca_cert);
let client_cert = tokio::fs::read("examples/data/tls/client1.pem").await?;
let client_key = tokio::fs::read("examples/data/tls/client1.key").await?;
let client_cert = std::fs::read_to_string(data_dir.join("tls/client1.pem"))?;
let client_key = std::fs::read_to_string(data_dir.join("tls/client1.key"))?;
let client_identity = Identity::from_pem(client_cert, client_key);

let tls = ClientTlsConfig::new()
37 changes: 5 additions & 32 deletions examples/src/tls_client_auth/server.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
pub mod pb {
tonic::include_proto!("grpc.examples.echo");
tonic::include_proto!("grpc.examples.unaryecho");
}

use futures::Stream;
use pb::{EchoRequest, EchoResponse};
use std::pin::Pin;
use tonic::transport::{Certificate, Identity, Server, ServerTlsConfig};
use tonic::{Request, Response, Status};

type EchoResult<T> = Result<Response<T>, Status>;
type ResponseStream = Pin<Box<dyn Stream<Item = Result<EchoResponse, Status>> + Send>>;

#[derive(Default)]
pub struct EchoServer;
@@ -26,40 +23,16 @@ impl pb::echo_server::Echo for EchoServer {
let message = request.into_inner().message;
Ok(Response::new(EchoResponse { message }))
}

type ServerStreamingEchoStream = ResponseStream;

async fn server_streaming_echo(
&self,
_: Request<EchoRequest>,
) -> Result<Response<Self::ServerStreamingEchoStream>, Status> {
Err(Status::unimplemented("Not yet implemented"))
}

async fn client_streaming_echo(
&self,
_: Request<tonic::Streaming<EchoRequest>>,
) -> Result<Response<EchoResponse>, Status> {
Err(Status::unimplemented("Not yet implemented"))
}

type BidirectionalStreamingEchoStream = ResponseStream;

async fn bidirectional_streaming_echo(
&self,
_: Request<tonic::Streaming<EchoRequest>>,
) -> Result<Response<Self::BidirectionalStreamingEchoStream>, Status> {
Err(Status::unimplemented("Not yet implemented"))
}
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let cert = tokio::fs::read("examples/data/tls/server.pem").await?;
let key = tokio::fs::read("examples/data/tls/server.key").await?;
let data_dir = std::path::PathBuf::from_iter([std::env!("CARGO_MANIFEST_DIR"), "data"]);
let cert = std::fs::read_to_string(data_dir.join("tls/server.pem"))?;
let key = std::fs::read_to_string(data_dir.join("tls/server.key"))?;
let server_identity = Identity::from_pem(cert, key);

let client_ca_cert = tokio::fs::read("examples/data/tls/client_ca.pem").await?;
let client_ca_cert = std::fs::read_to_string(data_dir.join("tls/client_ca.pem"))?;
let client_ca_cert = Certificate::from_pem(client_ca_cert);

let addr = "[::1]:50051".parse().unwrap();
Original file line number Diff line number Diff line change
@@ -2,16 +2,19 @@
//! provide a custom `ClientConfig` for the tls configuration.
pub mod pb {
tonic::include_proto!("/grpc.examples.echo");
tonic::include_proto!("/grpc.examples.unaryecho");
}

use std::iter::FromIterator;

use hyper::{client::HttpConnector, Uri};
use pb::{echo_client::EchoClient, EchoRequest};
use tokio_rustls::rustls::{ClientConfig, RootCertStore};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let fd = std::fs::File::open("examples/data/tls/ca.pem")?;
let data_dir = std::path::PathBuf::from_iter([std::env!("CARGO_MANIFEST_DIR"), "data"]);
let fd = std::fs::File::open(data_dir.join("tls/ca.pem"))?;

let mut roots = RootCertStore::empty();

Original file line number Diff line number Diff line change
@@ -1,39 +1,39 @@
pub mod pb {
tonic::include_proto!("/grpc.examples.echo");
tonic::include_proto!("/grpc.examples.unaryecho");
}

use futures::Stream;
use hyper::server::conn::Http;
use pb::{EchoRequest, EchoResponse};
use std::{pin::Pin, sync::Arc};
use std::sync::Arc;
use tokio::net::TcpListener;
use tokio_rustls::{
rustls::{Certificate, PrivateKey, ServerConfig},
TlsAcceptor,
};
use tonic::{transport::Server, Request, Response, Status, Streaming};
use tonic::{transport::Server, Request, Response, Status};
use tower_http::ServiceBuilderExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let data_dir = std::path::PathBuf::from_iter([std::env!("CARGO_MANIFEST_DIR"), "data"]);
let certs = {
let fd = std::fs::File::open("examples/data/tls/server.pem")?;
let fd = std::fs::File::open(data_dir.join("tls/server.pem"))?;
let mut buf = std::io::BufReader::new(&fd);
rustls_pemfile::certs(&mut buf)?
.into_iter()
.map(Certificate)
.collect()
};
let key = {
let fd = std::fs::File::open("examples/data/tls/server.key")?;
let fd = std::fs::File::open(data_dir.join("tls/server.key"))?;
let mut buf = std::io::BufReader::new(&fd);
rustls_pemfile::pkcs8_private_keys(&mut buf)?
.into_iter()
.map(PrivateKey)
.next()
.unwrap()

// let key = std::fs::read("examples/data/tls/server.key")?;
// let key = std::fs::read(data_dir.join("tls/server.key"))?;
// PrivateKey(key)
};

@@ -98,7 +98,6 @@ struct ConnInfo {
}

type EchoResult<T> = Result<Response<T>, Status>;
type ResponseStream = Pin<Box<dyn Stream<Item = Result<EchoResponse, Status>> + Send>>;

#[derive(Default)]
pub struct EchoServer;
@@ -115,29 +114,4 @@ impl pb::echo_server::Echo for EchoServer {
let message = request.into_inner().message;
Ok(Response::new(EchoResponse { message }))
}

type ServerStreamingEchoStream = ResponseStream;

async fn server_streaming_echo(
&self,
_: Request<EchoRequest>,
) -> EchoResult<Self::ServerStreamingEchoStream> {
Err(Status::unimplemented("not implemented"))
}

async fn client_streaming_echo(
&self,
_: Request<Streaming<EchoRequest>>,
) -> EchoResult<EchoResponse> {
Err(Status::unimplemented("not implemented"))
}

type BidirectionalStreamingEchoStream = ResponseStream;

async fn bidirectional_streaming_echo(
&self,
_: Request<Streaming<EchoRequest>>,
) -> EchoResult<Self::BidirectionalStreamingEchoStream> {
Err(Status::unimplemented("not implemented"))
}
}
3 changes: 1 addition & 2 deletions examples/src/tracing/client.rs
Original file line number Diff line number Diff line change
@@ -3,7 +3,6 @@ pub mod hello_world {
}

use hello_world::{greeter_client::GreeterClient, HelloRequest};
use tracing_attributes::instrument;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
@@ -16,7 +15,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
Ok(())
}

#[instrument]
#[tracing::instrument]
async fn say_hi(name: String) -> Result<(), Box<dyn std::error::Error>> {
let mut client = GreeterClient::connect("http://[::1]:50051").await?;

1 change: 0 additions & 1 deletion examples/src/uds/client.rs
Original file line number Diff line number Diff line change
@@ -5,7 +5,6 @@ pub mod hello_world {
}

use hello_world::{greeter_client::GreeterClient, HelloRequest};
use std::convert::TryFrom;
#[cfg(unix)]
use tokio::net::UnixStream;
use tonic::transport::{Endpoint, Uri};
2 changes: 1 addition & 1 deletion examples/src/uds/server.rs
Original file line number Diff line number Diff line change
@@ -45,7 +45,7 @@ impl Greeter for MyGreeter {
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let path = "/tmp/tonic/helloworld";

tokio::fs::create_dir_all(Path::new(path).parent().unwrap()).await?;
std::fs::create_dir_all(Path::new(path).parent().unwrap())?;

let greeter = MyGreeter::default();

14 changes: 8 additions & 6 deletions interop/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
authors = ["Lucio Franco <luciofranco14@gmail.com>"]
edition = "2018"
edition = "2021"
license = "MIT"
name = "interop"
publish = false
@@ -16,17 +16,16 @@ path = "src/bin/server.rs"

[dependencies]
async-stream = "0.3"
bytes = "1.0"
clap = {version = "4.0.26", features = ["derive"]}
console = "0.14"
strum = {version = "0.24", features = ["derive"]}
pico-args = {version = "0.5", features = ["eq-separator"]}
console = "0.15"
futures-core = "0.3"
futures-util = "0.3"
http = "0.2"
http-body = "0.4.2"
hyper = "0.14"
prost = "0.11"
prost-derive = "0.11"
tokio = {version = "1.0", features = ["rt-multi-thread", "time", "macros", "fs"]}
tokio = {version = "1.0", features = ["rt-multi-thread", "time", "macros"]}
tokio-stream = "0.1"
tonic = {path = "../tonic", features = ["tls"]}
tower = {version = "0.4"}
@@ -36,3 +35,6 @@ tracing-subscriber = {version = "0.3", features = ["env-filter"]}

[build-dependencies]
tonic-build = {path = "../tonic-build", features = ["prost"]}

[package.metadata.cargo-machete]
ignored = ["prost"]
34 changes: 18 additions & 16 deletions interop/src/bin/client.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,31 @@
use clap::{ArgAction, Parser};
use interop::client;
use std::time::Duration;
use std::{str::FromStr, time::Duration};
use tonic::transport::Endpoint;
use tonic::transport::{Certificate, ClientTlsConfig};

#[derive(Parser)]
#[derive(Debug)]
struct Opts {
#[clap(name = "use_tls", long, action = ArgAction::SetTrue)]
use_tls: bool,

#[arg(
long = "test_case",
use_value_delimiter = true,
num_args(1..),
value_enum,
action = ArgAction::Append
)]
test_case: Vec<Testcase>,
}

impl Opts {
fn parse() -> Result<Self, pico_args::Error> {
let mut pargs = pico_args::Arguments::from_env();
Ok(Self {
use_tls: pargs.contains("--use_tls"),
test_case: pargs.value_from_fn("--test_case", |test_case| {
test_case.split(',').map(Testcase::from_str).collect()
})?,
})
}
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
interop::trace_init();

let matches = Opts::parse();
let matches = Opts::parse()?;

let test_cases = matches.test_case;

@@ -33,7 +35,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
.concurrency_limit(30);

if matches.use_tls {
let pem = tokio::fs::read("interop/data/ca.pem").await?;
let pem = std::fs::read_to_string("interop/data/ca.pem")?;
let ca = Certificate::from_pem(pem);
endpoint = endpoint.tls_config(
ClientTlsConfig::new()
@@ -99,8 +101,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
Ok(())
}

#[derive(Debug, Copy, Clone, clap::ValueEnum)]
#[clap(rename_all = "snake_case")]
#[derive(Debug, strum::EnumString)]
#[strum(serialize_all = "snake_case")]
enum Testcase {
EmptyUnary,
CacheableUnary,
19 changes: 13 additions & 6 deletions interop/src/bin/server.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,34 @@
use clap::{ArgAction, Parser};
use interop::server;
use tonic::transport::Server;
use tonic::transport::{Identity, ServerTlsConfig};

#[derive(Parser)]
#[derive(Debug)]
struct Opts {
#[clap(name = "use_tls", long, action = ArgAction::SetTrue)]
use_tls: bool,
}

impl Opts {
fn parse() -> Result<Self, pico_args::Error> {
let mut pargs = pico_args::Arguments::from_env();
Ok(Self {
use_tls: pargs.contains("--use_tls"),
})
}
}

#[tokio::main]
async fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
interop::trace_init();

let matches = Opts::parse();
let matches = Opts::parse()?;

let addr = "127.0.0.1:10000".parse().unwrap();

let mut builder = Server::builder();

if matches.use_tls {
let cert = tokio::fs::read("interop/data/server1.pem").await?;
let key = tokio::fs::read("interop/data/server1.key").await?;
let cert = std::fs::read_to_string("interop/data/server1.pem")?;
let key = std::fs::read_to_string("interop/data/server1.key")?;
let identity = Identity::from_pem(cert, key);

builder = builder.tls_config(ServerTlsConfig::new().identity(identity))?;
6 changes: 3 additions & 3 deletions interop/src/lib.rs
Original file line number Diff line number Diff line change
@@ -113,7 +113,7 @@ impl fmt::Display for TestAssertion {
macro_rules! test_assert {
($description:expr, $assertion:expr) => {
if $assertion {
crate::TestAssertion::Passed {
$crate::TestAssertion::Passed {
description: $description,
}
} else {
@@ -126,11 +126,11 @@ macro_rules! test_assert {
};
($description:expr, $assertion:expr, $why:expr) => {
if $assertion {
crate::TestAssertion::Passed {
$crate::TestAssertion::Passed {
description: $description,
}
} else {
crate::TestAssertion::Failed {
$crate::TestAssertion::Failed {
description: $description,
expression: stringify!($assertion),
why: Some($why),
2 changes: 1 addition & 1 deletion rustfmt.toml
Original file line number Diff line number Diff line change
@@ -1 +1 @@
edition = "2018"
edition = "2021"
5 changes: 4 additions & 1 deletion tests/ambiguous_methods/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
authors = ["Yonathan Randolph <yonathan@gmail.com>"]
edition = "2018"
edition = "2021"
license = "MIT"
name = "ambiguous_methods"
publish = false
@@ -14,3 +14,6 @@ tonic = {path = "../../tonic"}

[build-dependencies]
tonic-build = {path = "../../tonic-build"}

[package.metadata.cargo-machete]
ignored = ["prost"]
8 changes: 5 additions & 3 deletions tests/compression/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
authors = ["Lucio Franco <luciofranco14@gmail.com>"]
edition = "2018"
edition = "2021"
license = "MIT"
name = "compression"
publish = false
@@ -15,10 +15,12 @@ hyper = "0.14.3"
pin-project = "1.0"
prost = "0.11"
tokio = {version = "1.0", features = ["macros", "rt-multi-thread", "net"]}
tokio-stream = {version = "0.1.5", features = ["net"]}
tonic = {path = "../../tonic", features = ["gzip"]}
tower = {version = "0.4", features = []}
tower-http = {version = "0.3", features = ["map-response-body", "map-request-body"]}
tower-http = {version = "0.4", features = ["map-response-body", "map-request-body"]}

[build-dependencies]
tonic-build = {path = "../../tonic-build" }

[package.metadata.cargo-machete]
ignored = ["prost"]
1 change: 0 additions & 1 deletion tests/compression/src/lib.rs
Original file line number Diff line number Diff line change
@@ -3,7 +3,6 @@
use self::util::*;
use crate::util::mock_io_channel;
use futures::{Stream, StreamExt};
use std::convert::TryFrom;
use std::{
pin::Pin,
sync::{
7 changes: 5 additions & 2 deletions tests/disable_comments/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
authors = ["bouzuya <m@bouzuya.net>"]
edition = "2018"
edition = "2021"
license = "MIT"
name = "disable-comments"
publish = false
@@ -13,5 +13,8 @@ prost = "0.11"
tonic = { path = "../../tonic" }

[build-dependencies]
prost-build = "0.11"
prost-build = "0.11.6"
tonic-build = { path = "../../tonic-build" }

[package.metadata.cargo-machete]
ignored = ["prost"]
2 changes: 1 addition & 1 deletion tests/disable_comments/build.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
fn main() {
let mut config = prost_build::Config::default();
config.disable_comments(&["test.Input1", "test.Output1"]);
config.disable_comments(["test.Input1", "test.Output1"]);
tonic_build::configure()
.disable_comments("test.Service1")
.disable_comments("test.Service1.Rpc1")
6 changes: 4 additions & 2 deletions tests/extern_path/my_application/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
authors = ["Danny Hua <danny@42layers.io>"]
edition = "2018"
edition = "2021"
license = "MIT"
name = "my_application"
publish = false
@@ -10,9 +10,11 @@ version = "0.1.0"

[dependencies]
prost = "0.11"
prost-types = "0.11"
tonic = {path = "../../../tonic"}
uuid = {package = "uuid1", path = "../uuid"}

[build-dependencies]
tonic-build = {path = "../../../tonic-build"}

[package.metadata.cargo-machete]
ignored = ["prost"]
8 changes: 5 additions & 3 deletions tests/extern_path/uuid/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
authors = ["Danny Hua <danny@42layers.io>"]
edition = "2018"
edition = "2021"
license = "MIT"
name = "uuid1"
publish = false
@@ -9,7 +9,9 @@ version = "0.1.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
bytes = "1.0"
prost = "0.11"
[build-dependencies]
prost-build = "0.11"
prost-build = "0.11.6"

[package.metadata.cargo-machete]
ignored = ["prost"]
5 changes: 4 additions & 1 deletion tests/included_service/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
authors = ["Lucio Franco <luciofranco14@gmail.com>"]
edition = "2018"
edition = "2021"
license = "MIT"
name = "included_service"
publish = false
@@ -14,3 +14,6 @@ tonic = {path = "../../tonic"}

[build-dependencies]
tonic-build = {path = "../../tonic-build"}

[package.metadata.cargo-machete]
ignored = ["prost"]
10 changes: 7 additions & 3 deletions tests/integration_tests/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
authors = ["Lucio Franco <luciofranco14@gmail.com>"]
edition = "2018"
edition = "2021"
license = "MIT"
name = "integration-tests"
publish = false
@@ -14,6 +14,7 @@ futures-util = "0.3"
prost = "0.11"
tokio = {version = "1.0", features = ["macros", "rt-multi-thread", "net"]}
tonic = {path = "../../tonic"}
tracing-subscriber = {version = "0.3", features = ["env-filter"]}

[dev-dependencies]
async-stream = "0.3"
@@ -23,9 +24,12 @@ http-body = "0.4"
hyper = "0.14"
tokio-stream = {version = "0.1.5", features = ["net"]}
tower = {version = "0.4", features = []}
tower-http = { version = "0.3", features = ["set-header", "trace"] }
tower-http = { version = "0.4", features = ["set-header", "trace"] }
tower-service = "0.3"
tracing-subscriber = {version = "0.3", features = ["env-filter"]}
tracing = "0.1"

[build-dependencies]
tonic-build = {path = "../../tonic-build"}

[package.metadata.cargo-machete]
ignored = ["prost"]
11 changes: 11 additions & 0 deletions tests/integration_tests/proto/test.proto
Original file line number Diff line number Diff line change
@@ -8,3 +8,14 @@ service Test {

message Input {}
message Output {}

service Test1 {
rpc UnaryCall(Input1) returns (Output1);
}

message Input1 {
bytes buf = 1;
}
message Output1 {
bytes buf = 1;
}
6 changes: 6 additions & 0 deletions tests/integration_tests/src/lib.rs
Original file line number Diff line number Diff line change
@@ -53,3 +53,9 @@ pub mod mock {
}
}
}

pub fn trace_init() {
let _ = tracing_subscriber::FmtSubscriber::builder()
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
.try_init();
}
4 changes: 2 additions & 2 deletions tests/integration_tests/tests/connect_info.rs
Original file line number Diff line number Diff line change
@@ -14,6 +14,7 @@ async fn getting_connect_info() {
#[tonic::async_trait]
impl test_server::Test for Svc {
async fn unary_call(&self, req: Request<Input>) -> Result<Response<Output>, Status> {
assert!(req.local_addr().is_some());
assert!(req.remote_addr().is_some());
assert!(req.extensions().get::<TcpConnectInfo>().is_some());

@@ -51,8 +52,6 @@ async fn getting_connect_info() {

#[cfg(unix)]
pub mod unix {
use std::convert::TryFrom as _;

use futures_util::FutureExt;
use tokio::{
net::{UnixListener, UnixStream},
@@ -75,6 +74,7 @@ pub mod unix {
let conn_info = req.extensions().get::<UdsConnectInfo>().unwrap();

// Client-side unix sockets are unnamed.
assert!(req.local_addr().is_none());
assert!(req.remote_addr().is_none());
assert!(conn_info.peer_addr.as_ref().unwrap().is_unnamed());
// This should contain process credentials for the client socket.
53 changes: 53 additions & 0 deletions tests/integration_tests/tests/interceptor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use std::time::Duration;

use futures::{channel::oneshot, FutureExt};
use integration_tests::pb::{test_client::TestClient, test_server, Input, Output};
use tonic::{
transport::{Endpoint, Server},
GrpcMethod, Request, Response, Status,
};

#[tokio::test]
async fn interceptor_retrieves_grpc_method() {
use test_server::Test;

struct Svc;

#[tonic::async_trait]
impl Test for Svc {
async fn unary_call(&self, _: Request<Input>) -> Result<Response<Output>, Status> {
Ok(Response::new(Output {}))
}
}

let svc = test_server::TestServer::new(Svc);

let (tx, rx) = oneshot::channel();
// Start the server now, second call should succeed
let jh = tokio::spawn(async move {
Server::builder()
.add_service(svc)
.serve_with_shutdown("127.0.0.1:1340".parse().unwrap(), rx.map(drop))
.await
.unwrap();
});

let channel = Endpoint::from_static("http://127.0.0.1:1340").connect_lazy();

fn client_intercept(req: Request<()>) -> Result<Request<()>, Status> {
println!("Intercepting client request: {:?}", req);

let gm = req.extensions().get::<GrpcMethod>().unwrap();
assert_eq!(gm.service(), "test.Test");
assert_eq!(gm.method(), "UnaryCall");

Ok(req)
}
let mut client = TestClient::with_interceptor(channel, client_intercept);

tokio::time::sleep(Duration::from_millis(100)).await;
client.unary_call(Request::new(Input {})).await.unwrap();

tx.send(()).unwrap();
jh.await.unwrap();
}
278 changes: 278 additions & 0 deletions tests/integration_tests/tests/max_message_size.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
use integration_tests::{
pb::{test1_client, test1_server, Input1, Output1},
trace_init,
};
use tonic::{
transport::{Endpoint, Server},
Code, Request, Response, Status,
};

#[test]
fn max_message_recv_size() {
trace_init();

// Server recv
assert_server_recv_max_success(128);
// 5 is the size of the gRPC header
assert_server_recv_max_success((4 * 1024 * 1024) - 5);
// 4mb is the max recv size
assert_server_recv_max_failure(4 * 1024 * 1024);
assert_server_recv_max_failure(4 * 1024 * 1024 + 1);
assert_server_recv_max_failure(8 * 1024 * 1024);

// Client recv
assert_client_recv_max_success(128);
// 5 is the size of the gRPC header
assert_client_recv_max_success((4 * 1024 * 1024) - 5);
// 4mb is the max recv size
assert_client_recv_max_failure(4 * 1024 * 1024);
assert_client_recv_max_failure(4 * 1024 * 1024 + 1);
assert_client_recv_max_failure(8 * 1024 * 1024);

// Custom limit settings
assert_test_case(TestCase {
// 5 is the size of the gRPC header
server_blob_size: 1024 - 5,
client_recv_max: Some(1024),
..Default::default()
});
assert_test_case(TestCase {
server_blob_size: 1024,
client_recv_max: Some(1024),
expected_code: Some(Code::OutOfRange),
..Default::default()
});

assert_test_case(TestCase {
// 5 is the size of the gRPC header
client_blob_size: 1024 - 5,
server_recv_max: Some(1024),
..Default::default()
});
assert_test_case(TestCase {
client_blob_size: 1024,
server_recv_max: Some(1024),
expected_code: Some(Code::OutOfRange),
..Default::default()
});
}

#[test]
fn max_message_send_size() {
trace_init();

// Check client send limit works
assert_test_case(TestCase {
client_blob_size: 4 * 1024 * 1024,
server_recv_max: Some(usize::MAX),
..Default::default()
});
assert_test_case(TestCase {
// 5 is the size of the gRPC header
client_blob_size: 1024 - 5,
server_recv_max: Some(usize::MAX),
client_send_max: Some(1024),
..Default::default()
});
assert_test_case(TestCase {
// 5 is the size of the gRPC header
client_blob_size: 4 * 1024 * 1024,
server_recv_max: Some(usize::MAX),
// Set client send limit to 1024
client_send_max: Some(1024),
// TODO: This should return OutOfRange
// https://github.com/hyperium/tonic/issues/1334
expected_code: Some(Code::Internal),
..Default::default()
});

// Check server send limit works
assert_test_case(TestCase {
server_blob_size: 4 * 1024 * 1024,
client_recv_max: Some(usize::MAX),
..Default::default()
});
assert_test_case(TestCase {
// 5 is the gRPC header size
server_blob_size: 1024 - 5,
client_recv_max: Some(usize::MAX),
// Set server send limit to 1024
server_send_max: Some(1024),
..Default::default()
});
assert_test_case(TestCase {
server_blob_size: 4 * 1024 * 1024,
client_recv_max: Some(usize::MAX),
// Set server send limit to 1024
server_send_max: Some(1024),
expected_code: Some(Code::OutOfRange),
..Default::default()
});
}

// Track caller doesn't work on async fn so we extract the async part
// into a sync version and assert the response there using track track_caller
// so that when this does panic it tells us which line in the test failed not
// where we placed the panic call.

#[track_caller]
fn assert_server_recv_max_success(size: usize) {
let case = TestCase {
client_blob_size: size,
server_blob_size: 0,
..Default::default()
};

assert_test_case(case);
}

#[track_caller]
fn assert_server_recv_max_failure(size: usize) {
let case = TestCase {
client_blob_size: size,
server_blob_size: 0,
expected_code: Some(Code::OutOfRange),
..Default::default()
};

assert_test_case(case);
}

#[track_caller]
fn assert_client_recv_max_success(size: usize) {
let case = TestCase {
client_blob_size: 0,
server_blob_size: size,
..Default::default()
};

assert_test_case(case);
}

#[track_caller]
fn assert_client_recv_max_failure(size: usize) {
let case = TestCase {
client_blob_size: 0,
server_blob_size: size,
expected_code: Some(Code::OutOfRange),
..Default::default()
};

assert_test_case(case);
}

#[track_caller]
fn assert_test_case(case: TestCase) {
let res = max_message_run(&case);

match (case.expected_code, res) {
(Some(_), Ok(())) => panic!("Expected failure, but got success"),
(Some(code), Err(status)) => {
if status.code() != code {
panic!(
"Expected failure, got failure but wrong code, got: {:?}",
status
)
}
}

(None, Err(status)) => panic!("Expected success, but got failure, got: {:?}", status),

_ => (),
}
}

#[derive(Default)]
struct TestCase {
client_blob_size: usize,
server_blob_size: usize,
client_recv_max: Option<usize>,
server_recv_max: Option<usize>,
client_send_max: Option<usize>,
server_send_max: Option<usize>,

expected_code: Option<Code>,
}

#[tokio::main]
async fn max_message_run(case: &TestCase) -> Result<(), Status> {
let client_blob = vec![0; case.client_blob_size];
let server_blob = vec![0; case.server_blob_size];

let (client, server) = tokio::io::duplex(1024);

struct Svc(Vec<u8>);

#[tonic::async_trait]
impl test1_server::Test1 for Svc {
async fn unary_call(&self, _req: Request<Input1>) -> Result<Response<Output1>, Status> {
Ok(Response::new(Output1 {
buf: self.0.clone(),
}))
}
}

let svc = test1_server::Test1Server::new(Svc(server_blob));

let svc = if let Some(size) = case.server_recv_max {
svc.max_decoding_message_size(size)
} else {
svc
};

let svc = if let Some(size) = case.server_send_max {
svc.max_encoding_message_size(size)
} else {
svc
};

tokio::spawn(async move {
Server::builder()
.add_service(svc)
.serve_with_incoming(futures::stream::iter(vec![Ok::<_, std::io::Error>(server)]))
.await
.unwrap();
});

// Move client to an option so we can _move_ the inner value
// on the first attempt to connect. All other attempts will fail.
let mut client = Some(client);
let channel = Endpoint::try_from("http://[::]:50051")
.unwrap()
.connect_with_connector(tower::service_fn(move |_| {
let client = client.take();

async move {
if let Some(client) = client {
Ok(client)
} else {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"Client already taken",
))
}
}
}))
.await
.unwrap();

let client = test1_client::Test1Client::new(channel);

let client = if let Some(size) = case.client_recv_max {
client.max_decoding_message_size(size)
} else {
client
};

let mut client = if let Some(size) = case.client_send_max {
client.max_encoding_message_size(size)
} else {
client
};

let req = Request::new(Input1 {
buf: client_blob.clone(),
});

client.unary_call(req).await.map(|_| ())
}
1 change: 0 additions & 1 deletion tests/integration_tests/tests/status.rs
Original file line number Diff line number Diff line change
@@ -6,7 +6,6 @@ use integration_tests::pb::{
test_client, test_server, test_stream_client, test_stream_server, Input, InputStream, Output,
OutputStream,
};
use std::convert::TryFrom;
use std::error::Error;
use std::time::Duration;
use tokio::sync::oneshot;
2 changes: 1 addition & 1 deletion tests/integration_tests/tests/streams.rs
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@ async fn status_from_server_stream_with_source() {
&self,
_: Request<InputStream>,
) -> Result<Response<Self::StreamCallStream>, Status> {
let s = Unsync(0 as *mut ());
let s = Unsync(std::ptr::null_mut::<()>());

Ok(Response::new(Box::pin(s) as Self::StreamCallStream))
}
2 changes: 1 addition & 1 deletion tests/root-crate-path/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
authors = ["Lucio Franco <luciofranco14@gmail.com>"]
edition = "2018"
edition = "2021"
license = "MIT"
name = "root-crate-path"
publish = false
1 change: 1 addition & 0 deletions tests/root-crate-path/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Animal {
#[prost(string, optional, tag = "1")]
5 changes: 4 additions & 1 deletion tests/same_name/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
authors = ["Lucio Franco <luciofranco14@gmail.com>"]
edition = "2018"
edition = "2021"
license = "MIT"
name = "same_name"
publish = false
@@ -14,3 +14,6 @@ tonic = {path = "../../tonic"}

[build-dependencies]
tonic-build = {path = "../../tonic-build"}

[package.metadata.cargo-machete]
ignored = ["prost"]
17 changes: 17 additions & 0 deletions tests/service_named_result/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "service_named_result"
version = "0.1.0"
edition = "2021"
publish = false

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
prost = "0.11"
tonic = {path = "../../tonic"}

[build-dependencies]
tonic-build = {path = "../../tonic-build"}

[package.metadata.cargo-machete]
ignored = ["prost"]
19 changes: 19 additions & 0 deletions tests/service_named_result/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Copyright (c) 2020 Lucio Franco

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
3 changes: 3 additions & 0 deletions tests/service_named_result/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
tonic_build::compile_protos("proto/result.proto").unwrap();
}
13 changes: 13 additions & 0 deletions tests/service_named_result/proto/result.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
syntax = "proto3";

import "google/protobuf/empty.proto";

package result;

service Result {
rpc Listen(google.protobuf.Empty) returns (Reply) {}
}

message Reply {
int32 step = 1;
}
3 changes: 3 additions & 0 deletions tests/service_named_result/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod pb {
tonic::include_proto!("result");
}
5 changes: 4 additions & 1 deletion tests/service_named_service/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
authors = ["Lucio Franco <luciofranco14@gmail.com>"]
edition = "2018"
edition = "2021"
license = "MIT"
name = "service_named_service"
publish = false
@@ -14,3 +14,6 @@ tonic = {path = "../../tonic"}

[build-dependencies]
tonic-build = {path = "../../tonic-build"}

[package.metadata.cargo-machete]
ignored = ["prost"]
5 changes: 4 additions & 1 deletion tests/stream_conflict/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
authors = ["Ben Sully <ben@bsull.io>"]
edition = "2018"
edition = "2021"
name = "stream_conflict"
publish = false
version = "0.1.0"
@@ -14,3 +14,6 @@ tonic = { path = "../../tonic" }

[build-dependencies]
tonic-build = { path = "../../tonic-build" }

[package.metadata.cargo-machete]
ignored = ["prost"]
7 changes: 5 additions & 2 deletions tests/wellknown-compiled/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
authors = ["Lucio Franco <luciofranco14@gmail.com>"]
edition = "2018"
edition = "2021"
license = "MIT"
name = "wellknown-compiled"
publish = false
@@ -16,5 +16,8 @@ prost = "0.11"
tonic = {path = "../../tonic"}

[build-dependencies]
prost-build = "0.11"
prost-build = "0.11.6"
tonic-build = {path = "../../tonic-build"}

[package.metadata.cargo-machete]
ignored = ["prost"]
5 changes: 4 additions & 1 deletion tests/wellknown/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
authors = ["Lucio Franco <luciofranco14@gmail.com>"]
edition = "2018"
edition = "2021"
license = "MIT"
name = "wellknown"
publish = false
@@ -15,3 +15,6 @@ tonic = {path = "../../tonic"}

[build-dependencies]
tonic-build = {path = "../../tonic-build"}

[package.metadata.cargo-machete]
ignored = ["prost", "prost-types"]
8 changes: 4 additions & 4 deletions tonic-build/Cargo.toml
Original file line number Diff line number Diff line change
@@ -4,20 +4,20 @@ categories = ["network-programming", "asynchronous"]
description = """
Codegen module of `tonic` gRPC implementation.
"""
documentation = "https://docs.rs/tonic-build/0.8.2/tonic_build/"
edition = "2018"
documentation = "https://docs.rs/tonic-build/0.9.0/tonic_build/"
edition = "2021"
homepage = "https://github.com/hyperium/tonic"
keywords = ["rpc", "grpc", "async", "codegen", "protobuf"]
license = "MIT"
name = "tonic-build"
readme = "README.md"
repository = "https://github.com/hyperium/tonic"
version = "0.8.3"
version = "0.9.0"

[dependencies]
prettyplease = { version = "0.1" }
proc-macro2 = "1.0"
prost-build = { version = "0.11.2", optional = true }
prost-build = { version = "0.11.6", optional = true }
quote = "1.0"
syn = "1.0"

156 changes: 99 additions & 57 deletions tonic-build/src/client.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use std::collections::HashSet;

use super::{Attributes, Method, Service};
use crate::{generate_doc_comments, naive_snake_case};
use crate::{
format_method_name, format_method_path, format_service_name, generate_doc_comments,
naive_snake_case,
};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};

@@ -51,21 +54,16 @@ pub(crate) fn generate_internal<T: Service>(
let connect = generate_connect(&service_ident, build_transport);

let package = if emit_package { service.package() } else { "" };
let path = format!(
"{}{}{}",
package,
if package.is_empty() { "" } else { "." },
service.identifier()
);
let service_name = format_service_name(service, emit_package);

let service_doc = if disable_comments.contains(&path) {
let service_doc = if disable_comments.contains(&service_name) {
TokenStream::new()
} else {
generate_doc_comments(service.comment())
};

let mod_attributes = attributes.for_mod(package);
let struct_attributes = attributes.for_struct(&path);
let struct_attributes = attributes.for_struct(&service_name);

quote! {
/// Generated client implementations.
@@ -137,6 +135,24 @@ pub(crate) fn generate_internal<T: Service>(
self
}

/// Limits the maximum size of a decoded message.
///
/// Default: `4MB`
#[must_use]
pub fn max_decoding_message_size(mut self, limit: usize) -> Self {
self.inner = self.inner.max_decoding_message_size(limit);
self
}

/// Limits the maximum size of an encoded message.
///
/// Default: `usize::MAX`
#[must_use]
pub fn max_encoding_message_size(mut self, limit: usize) -> Self {
self.inner = self.inner.max_encoding_message_size(limit);
self
}

#methods
}
}
@@ -150,7 +166,7 @@ fn generate_connect(service_ident: &syn::Ident, enabled: bool) -> TokenStream {
/// Attempt to create a new client by connecting to a given endpoint.
pub async fn connect<D>(dst: D) -> Result<Self, tonic::transport::Error>
where
D: std::convert::TryInto<tonic::transport::Endpoint>,
D: TryInto<tonic::transport::Endpoint>,
D::Error: Into<StdError>,
{
let conn = tonic::transport::Endpoint::new(dst)?.connect().await?;
@@ -179,36 +195,41 @@ fn generate_methods<T: Service>(
disable_comments: &HashSet<String>,
) -> TokenStream {
let mut stream = TokenStream::new();
let package = if emit_package { service.package() } else { "" };

for method in service.methods() {
let path = format!(
"/{}{}{}/{}",
package,
if package.is_empty() { "" } else { "." },
service.identifier(),
method.identifier()
);

if !disable_comments.contains(&format!(
"{}{}{}.{}",
package,
if package.is_empty() { "" } else { "." },
service.identifier(),
method.identifier()
)) {
if !disable_comments.contains(&format_method_name(service, method, emit_package)) {
stream.extend(generate_doc_comments(method.comment()));
}

let method = match (method.client_streaming(), method.server_streaming()) {
(false, false) => generate_unary(method, proto_path, compile_well_known_types, path),
(false, true) => {
generate_server_streaming(method, proto_path, compile_well_known_types, path)
}
(true, false) => {
generate_client_streaming(method, proto_path, compile_well_known_types, path)
}
(true, true) => generate_streaming(method, proto_path, compile_well_known_types, path),
(false, false) => generate_unary(
service,
method,
emit_package,
proto_path,
compile_well_known_types,
),
(false, true) => generate_server_streaming(
service,
method,
emit_package,
proto_path,
compile_well_known_types,
),
(true, false) => generate_client_streaming(
service,
method,
emit_package,
proto_path,
compile_well_known_types,
),
(true, true) => generate_streaming(
service,
method,
emit_package,
proto_path,
compile_well_known_types,
),
};

stream.extend(method);
@@ -217,105 +238,126 @@ fn generate_methods<T: Service>(
stream
}

fn generate_unary<T: Method>(
method: &T,
fn generate_unary<T: Service>(
service: &T,
method: &T::Method,
emit_package: bool,
proto_path: &str,
compile_well_known_types: bool,
path: String,
) -> TokenStream {
let codec_name = syn::parse_str::<syn::Path>(method.codec_path()).unwrap();
let ident = format_ident!("{}", method.name());
let (request, response) = method.request_response_name(proto_path, compile_well_known_types);
let service_name = format_service_name(service, emit_package);
let path = format_method_path(service, method, emit_package);
let method_name = method.identifier();

quote! {
pub async fn #ident(
&mut self,
request: impl tonic::IntoRequest<#request>,
) -> Result<tonic::Response<#response>, tonic::Status> {
) -> std::result::Result<tonic::Response<#response>, tonic::Status> {
self.inner.ready().await.map_err(|e| {
tonic::Status::new(tonic::Code::Unknown, format!("Service was not ready: {}", e.into()))
})?;
let codec = #codec_name::default();
let path = http::uri::PathAndQuery::from_static(#path);
self.inner.unary(request.into_request(), path, codec).await
let mut req = request.into_request();
req.extensions_mut().insert(GrpcMethod::new(#service_name, #method_name));
self.inner.unary(req, path, codec).await
}
}
}

fn generate_server_streaming<T: Method>(
method: &T,
fn generate_server_streaming<T: Service>(
service: &T,
method: &T::Method,
emit_package: bool,
proto_path: &str,
compile_well_known_types: bool,
path: String,
) -> TokenStream {
let codec_name = syn::parse_str::<syn::Path>(method.codec_path()).unwrap();
let ident = format_ident!("{}", method.name());

let (request, response) = method.request_response_name(proto_path, compile_well_known_types);
let service_name = format_service_name(service, emit_package);
let path = format_method_path(service, method, emit_package);
let method_name = method.identifier();

quote! {
pub async fn #ident(
&mut self,
request: impl tonic::IntoRequest<#request>,
) -> Result<tonic::Response<tonic::codec::Streaming<#response>>, tonic::Status> {
) -> std::result::Result<tonic::Response<tonic::codec::Streaming<#response>>, tonic::Status> {
self.inner.ready().await.map_err(|e| {
tonic::Status::new(tonic::Code::Unknown, format!("Service was not ready: {}", e.into()))
})?;
let codec = #codec_name::default();
let path = http::uri::PathAndQuery::from_static(#path);
self.inner.server_streaming(request.into_request(), path, codec).await
let mut req = request.into_request();
req.extensions_mut().insert(GrpcMethod::new(#service_name, #method_name));
self.inner.server_streaming(req, path, codec).await
}
}
}

fn generate_client_streaming<T: Method>(
method: &T,
fn generate_client_streaming<T: Service>(
service: &T,
method: &T::Method,
emit_package: bool,
proto_path: &str,
compile_well_known_types: bool,
path: String,
) -> TokenStream {
let codec_name = syn::parse_str::<syn::Path>(method.codec_path()).unwrap();
let ident = format_ident!("{}", method.name());

let (request, response) = method.request_response_name(proto_path, compile_well_known_types);
let service_name = format_service_name(service, emit_package);
let path = format_method_path(service, method, emit_package);
let method_name = method.identifier();

quote! {
pub async fn #ident(
&mut self,
request: impl tonic::IntoStreamingRequest<Message = #request>
) -> Result<tonic::Response<#response>, tonic::Status> {
) -> std::result::Result<tonic::Response<#response>, tonic::Status> {
self.inner.ready().await.map_err(|e| {
tonic::Status::new(tonic::Code::Unknown, format!("Service was not ready: {}", e.into()))
})?;
let codec = #codec_name::default();
let path = http::uri::PathAndQuery::from_static(#path);
self.inner.client_streaming(request.into_streaming_request(), path, codec).await
let mut req = request.into_streaming_request();
req.extensions_mut().insert(GrpcMethod::new(#service_name, #method_name));
self.inner.client_streaming(req, path, codec).await
}
}
}

fn generate_streaming<T: Method>(
method: &T,
fn generate_streaming<T: Service>(
service: &T,
method: &T::Method,
emit_package: bool,
proto_path: &str,
compile_well_known_types: bool,
path: String,
) -> TokenStream {
let codec_name = syn::parse_str::<syn::Path>(method.codec_path()).unwrap();
let ident = format_ident!("{}", method.name());

let (request, response) = method.request_response_name(proto_path, compile_well_known_types);
let service_name = format_service_name(service, emit_package);
let path = format_method_path(service, method, emit_package);
let method_name = method.identifier();

quote! {
pub async fn #ident(
&mut self,
request: impl tonic::IntoStreamingRequest<Message = #request>
) -> Result<tonic::Response<tonic::codec::Streaming<#response>>, tonic::Status> {
) -> std::result::Result<tonic::Response<tonic::codec::Streaming<#response>>, tonic::Status> {
self.inner.ready().await.map_err(|e| {
tonic::Status::new(tonic::Code::Unknown, format!("Service was not ready: {}", e.into()))
})?;
let codec = #codec_name::default();
let path = http::uri::PathAndQuery::from_static(#path);
self.inner.streaming(request.into_streaming_request(), path, codec).await
let mut req = request.into_streaming_request();
req.extensions_mut().insert(GrpcMethod::new(#service_name,#method_name));
self.inner.streaming(req, path, codec).await
}
}
}
6 changes: 3 additions & 3 deletions tonic-build/src/code_gen.rs
Original file line number Diff line number Diff line change
@@ -6,15 +6,15 @@ use crate::{Attributes, Service};

/// Builder for the generic code generation of server and clients.
#[derive(Debug)]
pub struct CodeGen8uilder {
pub struct CodeGenBuilder {
emit_package: bool,
compile_well_known_types: bool,
attributes: Attributes,
build_transport: bool,
disable_comments: HashSet<String>,
}

impl CodeGen8uilder {
impl CodeGenBuilder {
/// Create a new code gen builder with default options.
pub fn new() -> Self {
Default::default()
@@ -89,7 +89,7 @@ impl CodeGen8uilder {
}
}

impl Default for CodeGen8uilder {
impl Default for CodeGenBuilder {
fn default() -> Self {
Self {
emit_package: true,
32 changes: 29 additions & 3 deletions tonic-build/src/lib.rs
Original file line number Diff line number Diff line change
@@ -70,7 +70,7 @@
html_logo_url = "https://raw.githubusercontent.com/tokio-rs/website/master/public/img/icons/tonic.svg"
)]
#![deny(rustdoc::broken_intra_doc_links)]
#![doc(html_root_url = "https://docs.rs/tonic-build/0.8.3")]
#![doc(html_root_url = "https://docs.rs/tonic-build/0.9.0")]
#![doc(issue_tracker_base_url = "https://github.com/hyperium/tonic/issues/")]
#![doc(test(no_crate_inject, attr(deny(rust_2018_idioms))))]
#![cfg_attr(docsrs, feature(doc_cfg))]
@@ -95,7 +95,7 @@ pub mod client;
pub mod server;

mod code_gen;
pub use code_gen::CodeGen8uilder;
pub use code_gen::CodeGenBuilder;

/// Service generation trait.
///
@@ -197,6 +197,32 @@ impl Attributes {
}
}

fn format_service_name<T: Service>(service: &T, emit_package: bool) -> String {
let package = if emit_package { service.package() } else { "" };
format!(
"{}{}{}",
package,
if package.is_empty() { "" } else { "." },
service.identifier(),
)
}

fn format_method_path<T: Service>(service: &T, method: &T::Method, emit_package: bool) -> String {
format!(
"/{}/{}",
format_service_name(service, emit_package),
method.identifier()
)
}

fn format_method_name<T: Service>(service: &T, method: &T::Method, emit_package: bool) -> String {
format!(
"{}.{}",
format_service_name(service, emit_package),
method.identifier()
)
}

// Generates attributes given a list of (`pattern`, `attribute`) pairs. If `pattern` matches `name`, `attribute` will be included.
fn generate_attributes<'a>(
name: &str,
@@ -218,7 +244,7 @@ fn generate_attributes<'a>(
fn generate_doc_comment<S: AsRef<str>>(comment: S) -> TokenStream {
let comment = comment.as_ref();

let comment = if !comment.starts_with(" ") {
let comment = if !comment.starts_with(' ') {
format!(" {}", comment)
} else {
comment.to_string()
6 changes: 3 additions & 3 deletions tonic-build/src/manual.rs
Original file line number Diff line number Diff line change
@@ -28,7 +28,7 @@
//! }
//! ```

use crate::code_gen::CodeGen8uilder;
use crate::code_gen::CodeGenBuilder;

use proc_macro2::TokenStream;
use quote::ToTokens;
@@ -352,7 +352,7 @@ struct ServiceGenerator {
impl ServiceGenerator {
fn generate(&mut self, service: &Service) {
if self.builder.build_server {
let server = CodeGen8uilder::new()
let server = CodeGenBuilder::new()
.emit_package(true)
.compile_well_known_types(false)
.generate_server(service, "");
@@ -361,7 +361,7 @@ impl ServiceGenerator {
}

if self.builder.build_client {
let client = CodeGen8uilder::new()
let client = CodeGenBuilder::new()
.emit_package(true)
.compile_well_known_types(false)
.build_transport(self.builder.build_transport)
51 changes: 48 additions & 3 deletions tonic-build/src/prost.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::code_gen::CodeGen8uilder;
use crate::code_gen::CodeGenBuilder;

use super::Attributes;
use proc_macro2::TokenStream;
@@ -20,9 +20,12 @@ pub fn configure() -> Builder {
build_server: true,
build_transport: true,
file_descriptor_set_path: None,
skip_protoc_run: false,
out_dir: None,
extern_path: Vec::new(),
field_attributes: Vec::new(),
message_attributes: Vec::new(),
enum_attributes: Vec::new(),
type_attributes: Vec::new(),
server_attributes: Attributes::default(),
client_attributes: Attributes::default(),
@@ -161,7 +164,7 @@ impl ServiceGenerator {
impl prost_build::ServiceGenerator for ServiceGenerator {
fn generate(&mut self, service: prost_build::Service, _buf: &mut String) {
if self.builder.build_server {
let server = CodeGen8uilder::new()
let server = CodeGenBuilder::new()
.emit_package(self.builder.emit_package)
.compile_well_known_types(self.builder.compile_well_known_types)
.attributes(self.builder.server_attributes.clone())
@@ -172,7 +175,7 @@ impl prost_build::ServiceGenerator for ServiceGenerator {
}

if self.builder.build_client {
let client = CodeGen8uilder::new()
let client = CodeGenBuilder::new()
.emit_package(self.builder.emit_package)
.compile_well_known_types(self.builder.compile_well_known_types)
.attributes(self.builder.client_attributes.clone())
@@ -222,9 +225,12 @@ pub struct Builder {
pub(crate) build_server: bool,
pub(crate) build_transport: bool,
pub(crate) file_descriptor_set_path: Option<PathBuf>,
pub(crate) skip_protoc_run: bool,
pub(crate) extern_path: Vec<(String, String)>,
pub(crate) field_attributes: Vec<(String, String)>,
pub(crate) type_attributes: Vec<(String, String)>,
pub(crate) message_attributes: Vec<(String, String)>,
pub(crate) enum_attributes: Vec<(String, String)>,
pub(crate) server_attributes: Attributes,
pub(crate) client_attributes: Attributes,
pub(crate) proto_path: String,
@@ -267,6 +273,14 @@ impl Builder {
self
}

/// In combination with with file_descriptor_set_path, this can be used to provide a file
/// descriptor set as an input file, rather than having prost-build generate the file by
/// calling protoc.
pub fn skip_protoc_run(mut self) -> Self {
self.skip_protoc_run = true;
self
}

/// Set the output directory to generate code to.
///
/// Defaults to the `OUT_DIR` environment variable.
@@ -306,6 +320,28 @@ impl Builder {
self
}

/// Add additional attribute to matched messages.
///
/// Passed directly to `prost_build::Config.message_attribute`.
pub fn message_attribute<P: AsRef<str>, A: AsRef<str>>(
mut self,
path: P,
attribute: A,
) -> Self {
self.message_attributes
.push((path.as_ref().to_string(), attribute.as_ref().to_string()));
self
}

/// Add additional attribute to matched enums.
///
/// Passed directly to `prost_build::Config.enum_attribute`.
pub fn enum_attribute<P: AsRef<str>, A: AsRef<str>>(mut self, path: P, attribute: A) -> Self {
self.enum_attributes
.push((path.as_ref().to_string(), attribute.as_ref().to_string()));
self
}

/// Add additional attribute to matched server `mod`s. Matches on the package name.
pub fn server_mod_attribute<P: AsRef<str>, A: AsRef<str>>(
mut self,
@@ -438,6 +474,9 @@ impl Builder {
if let Some(path) = self.file_descriptor_set_path.as_ref() {
config.file_descriptor_set_path(path);
}
if self.skip_protoc_run {
config.skip_protoc_run();
}
for (proto_path, rust_path) in self.extern_path.iter() {
config.extern_path(proto_path, rust_path);
}
@@ -447,6 +486,12 @@ impl Builder {
for (prost_path, attr) in self.type_attributes.iter() {
config.type_attribute(prost_path, attr);
}
for (prost_path, attr) in self.message_attributes.iter() {
config.message_attribute(prost_path, attr);
}
for (prost_path, attr) in self.enum_attributes.iter() {
config.enum_attribute(prost_path, attr);
}
if self.compile_well_known_types {
config.compile_well_known_types();
}
Loading