You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从.proto文件获取消息对应的prost_types::DescriptorProto?

Rust调用BigQuery Storage写入API问题:从.proto文件获取DescriptorProto结构体

我用Rust编写了一个程序,通过gcloud-sdk的google.cloud.bigquery.storage.v1,借助gRPC和Protobuf调用Google BigQuery Storage写入API。

报错信息

2023-02-17T08:16:04.492220Z DEBUG gcloud_sdk::middleware: OK: /google.cloud.bigquery.storage.v1.BigQueryWrite/AppendRows took 262ms (incl. token gen: 0ms) Error: Status { code: InvalidArgument, message: "Invalid proto schema: BqMessage.proto: my.proto: "my.proto" is not a valid identifier. Entity: projects/steam-sequencer-xxxxxx/datasets/my_dataset/tables/test_table/streams/_default", source: None }

核心困惑

我对ProtoSchema结构体的参数存在疑问,它的定义如下:

pub struct ProtoSchema {
    pub proto_descriptor: Option<DescriptorProto>,
}

ProtoSchema用于描述序列化Protocol Buffer数据行的schema,其中proto_descriptor字段类型为prost_types::DescriptorProto。很多语言里这个类型可通过语言或包原生生成,但我作为Rust、Prost和gRPC新手,不知道如何通过Prost/Tonic crate从.proto文件获取DescriptorProto结构体。

我编写的相关代码

let x = DescriptorProto {
    name: Some(String::from("my.proto")),
    field: vec![],
    extension: vec![],
    nested_type: vec![],
    enum_type: vec![],
    extension_range: vec![],
    oneof_decl: vec![],
    options: None,
    reserved_range: vec![],
    reserved_name: vec![],
};

let proto_schema = ProtoSchema {
    proto_descriptor: Some(x),
};

let proto_data = ProtoData {
    writer_schema: Some(proto_schema),
    rows: Some(proto_rows),
};

解决方案

1. 先解决报错根源

你手动构造的DescriptorProto把name设为了"my.proto",但这个字段需要的是proto消息类型的名称(比如MyMessage),而非.proto文件名,这就是报错"my.proto" is not a valid identifier的直接原因。

2. 从.proto文件生成DescriptorProto的正确步骤

步骤1:配置Cargo.toml

确保依赖包含prost、prost-types、prost-build及tonic:

[dependencies]
prost = "0.12"
prost-types = "0.12"
tonic = "0.10"

[build-dependencies]
prost-build = "0.12"

步骤2:编写build.rs编译proto文件

在项目根目录创建build.rs,启用描述符生成选项:

fn main() -> Result<(), Box<dyn std::error::Error>> {
    prost_build::Config::new()
        // 指定生成的描述符集文件路径
        .file_descriptor_set_path("src/proto_descriptor.bin")
        // 编译你的proto文件,替换为实际路径
        .compile_protos(&["src/my.proto"], &["src/"])?;
    Ok(())
}

步骤3:加载描述符集并提取DescriptorProto

编译后会生成proto_descriptor.bin,运行时加载并解析出目标DescriptorProto:

use prost_types::{FileDescriptorSet, DescriptorProto};
use std::fs::read;

fn load_target_descriptor() -> Option<DescriptorProto> {
    // 读取描述符集文件
    let descriptor_bytes = read("src/proto_descriptor.bin").ok()?;
    let file_set = FileDescriptorSet::decode(&descriptor_bytes[..]).ok()?;
    
    // 找到目标消息的DescriptorProto,替换为你的消息类型名
    file_set.file.into_iter()
        .find(|file| file.name.as_deref() == Some("my.proto"))?
        .message_type.into_iter()
        .find(|msg| msg.name.as_deref() == Some("MyMessage"))
}

// 在业务代码中使用
let descriptor_proto = load_target_descriptor().expect("加载DescriptorProto失败");
let proto_schema = ProtoSchema {
    proto_descriptor: Some(descriptor_proto),
};

步骤4:确保proto文件定义规范

你的my.proto需要包含合法的消息定义,示例:

syntax = "proto3";

message MyMessage {
  string id = 1;
  int64 value = 2;
  // 其他业务字段...
}

3. 额外注意事项

  • 确保BigQuery表的schema与proto消息字段完全匹配,包括字段名、数据类型
  • 验证proto_rows的序列化格式与proto_schema定义一致,避免数据格式不匹配问题

内容的提问来源于stack exchange,提问作者WENPIN1

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 04:09:28