Rust Protocol Buffers代码生成插件protoc-gen-prost-crate的使用,高效生成类型安全gRPC和Protobuf Rust代码

protoc-gen-prost-crate 完整示例

以下是基于提供内容的完整示例演示如何使用protoc-gen-prost-crate生成Rust代码:

1. 安装protoc-gen-prost-crate

cargo install protoc-gen-prost-crate

2. 创建项目结构

my_proto_project/
├── proto/
│   └── greeter/
│       └── v1/
│           └── greeter.proto
└── buf.gen.yaml

3. greeter.proto文件内容

syntax = "proto3";

package greeter.v1;

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloResponse);
}

message HelloRequest {
  string name = 1;  // 请求中包含的名字
}

message HelloResponse {
  string message = 1;  // 返回的问候消息
}

4. buf.gen.yaml配置

version: v1
plugins:
  - plugin: prost
    out: gen/src
    opt:
      - bytes=.  # 生成字节数组支持
      - file_descriptor_set  # 生成文件描述符集
  - plugin: prost-crate
    out: gen
    strategy: all  # 使用all策略查看完整protobuf模式
    opt:
      - gen_crate  # 生成Cargo crate
      - only_include=.greeter  # 只包含greeter包

5. 运行代码生成

cd my_proto_project
buf generate

6. 生成的文件结构

gen/
├── Cargo.toml
└── src
    ├── greeter.v1.rs  # 生成的Rust protobuf代码
    └── lib.rs         # 包含文件和模块定义

7. 生成的Cargo.toml内容

[package]
name = "greeter-proto"
version = "0.1.0"
edition = "2021"

[dependencies]
prost = "0.10.0"

[features]
default = ["proto_full"]
## @@protoc_deletion_point(features)
## This section is automatically generated by protoc-gen-prost-crate. 
## Changes in this area may be lost on regeneration.
proto_full = ["greeter-v1"]
"greeter-v1" = []
## @@protoc_insertion_point(features)

8. 生成的lib.rs内容

#[cfg(feature = "greeter-v1")]
pub mod greeter {
    pub mod v1 {
        include!("greeter.v1.rs");  // 包含生成的protobuf代码
    }
}

9. 在项目中使用的示例

use greeter_proto::greeter::v1::{HelloRequest, HelloResponse};

fn main() {
    let request = HelloRequest {
        name: "World".to_string(),
    };
    
    println!("Sending request: {:?}", request);
}

关键点说明

  1. 多语言支持:这个工具特别适合在多语言环境中使用Protocol Buffers的情况

  2. 功能特性

    • 自动生成Cargo crate
    • 支持条件编译功能标志
    • 与buf工具链集成
  3. 代码组织

    • 生成的代码放在单独目录(gen/)
    • 通过include!宏包含生成代码
    • 保持生成代码与自定义代码分离
  4. 优势

    • 简化多语言项目的protobuf代码生成
    • 自动管理功能标志和模块组织
    • 与现有Protocol Buffers工具链良好集成

这个示例展示了如何从protobuf定义开始,通过protoc-gen-prost-crate生成完整的Rust crate,最后在项目中使用的完整流程。


1 回复

Rust Protocol Buffers代码生成插件protoc-gen-prost-crate使用指南

以下是基于您提供的内容整理的完整示例:

完整示例代码

项目结构

grpc-example/
├── proto/
│   └── greeter.proto
├── crates/
├── build.rs
└── Cargo.toml

proto/greeter.proto

syntax = "proto3";

package greeter;

service GreeterService {
  rpc SayHello (HelloRequest) returns (HelloResponse);
}

message HelloRequest {
  string name = 1;
}

message HelloResponse {
  string message = 1;
  int32 response_code = 2;
}

build.rs

// 设置构建脚本
fn main() -> std::io::Result<()> {
    // 确保protoc编译器可用
    std::env::set_var("PROTOC", protoc_bin_vendored::protoc_bin_path().unwrap());
    
    // 配置代码生成参数
    protoc_gen_prost_crate::run(protoc_gen_prost_crate::Args {
        out_dir: "crates",          // 输出目录
        includes: &["proto"],       // proto文件搜索路径
        input: &["proto/greeter.proto"],  // 输入proto文件
        rustfmt: true,              // 自动格式化生成的代码
        default_package_filename: "grpc_api",  // 默认包名
        ..Default::default()
    })
}

Cargo.toml

[package]
name = "grpc-example"
version = "0.1.0"
edition = "2021"

[build-dependencies]
protoc-bin-vendored = "3.0.0"          # 提供protoc编译器
protoc-gen-prost-crate = "0.3.0"       # 代码生成插件

[dependencies]
grpc-api = { path = "crates/grpc-api" } # 生成的crate
tokio = { version = "1.0", features = ["full"] } # 异步运行时
tonic = "0.8"                          # gRPC框架

服务端实现 src/main.rs

use grpc_api::greeter_service_server::{GreeterService, GreeterServiceServer};
use grpc_api::{HelloRequest, HelloResponse};
use tonic::{Request, Response, Status};

// 实现GreeterService trait
#[derive(Debug, Default)]
pub struct MyGreeter;

#[tonic::async_trait]
impl GreeterService for MyGreeter {
    async fn say_hello(
        &self,
        request: Request<HelloRequest>,  // 接收请求
    ) -> Result<Response<HelloResponse>, Status> {
        // 处理请求
        let name = request.into_inner().name;
        
        // 构建响应
        let reply = HelloResponse {
            message: format!("Hello, {}!", name),
            response_code: 200,
        };
        
        Ok(Response::new(reply))
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 设置服务地址
    let addr = "[::1]:50051".parse()?;
    let greeter = MyGreeter::default();

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

    // 启动gRPC服务
    tonic::transport::Server::builder()
        .add_service(GreeterServiceServer::new(greeter))
        .serve(addr)
        .await?;

    Ok(())
}

客户端示例 src/client.rs

use grpc_api::greeter_service_client::GreeterServiceClient;
use grpc_api::HelloRequest;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 创建客户端连接
    let mut client = GreeterServiceClient::connect("http://[::1]:50051").await?;

    // 准备请求
    let request = tonic::Request::new(HelloRequest {
        name: "Tonic".into(),
    });

    // 发送请求并获取响应
    let response = client.say_hello(request).await?;

    println!("RESPONSE={:?}", response.into_inner());

    Ok(())
}

使用说明

  1. 首先安装所需工具:
cargo install protoc-gen-prost-crate
  1. 构建项目:
cargo build
  1. 运行服务端:
cargo run
  1. 在另一个终端运行客户端测试:
cargo run --bin client

关键点说明

  1. 自动生成的代码位于crates/grpc-api目录
  2. 服务实现只需关注业务逻辑,框架代码由插件自动生成
  3. 客户端和服务端共享相同的Protobuf定义,确保类型安全
  4. 项目会自动处理所有gRPC和Protobuf相关依赖

这个完整示例展示了如何使用protoc-gen-prost-crate从定义Protobuf文件到实现完整的gRPC服务的过程,涵盖了服务端和客户端的实现。

回到顶部