げっとシステムログ

WEB開発メモ

Rust でも protobuf したい

CONTENTS
  1. protobuf で protobuf する
  2. protobuf-codegen-pure でコード生成
  3. 親モジュールのコードを生成
  4. actix-web でレスポンスを返す
  5. まとめ
  6. 参考資料
ENVIRONMENTS
  • rust: 1.51.0

protobuf で protobuf する

protobuf を使って protobuf することにする。 理由は探したとき最初に出てきたから、くらい。

TOP

protobuf-codegen-pure でコード生成

build.rs にコード生成のためのコードを追加する。

use protobuf_codegen_pure::Codegen

fn main() {
    Codegen::new()
        .out_dir("path/to/out")
        .inputs(&["path/to/source/example.proto"])
        .include("path/to/source")
        .run()
        .expect("failed to codegen")
}

せっかくなので pure rust のコードを使用することにする。 protoc コマンドをインストールしなくていい rust 実装を使いたい。 ドキュメントにはバグがあったら教えてねって書いてあるけど。 特殊なことをするつもりはないので、大丈夫だろうと判断した。

TOP

親モジュールのコードを生成

上記コードで、hello.proto から hello.rs が生成される。

実際には複数の proto ファイルを 1 つのディレクトリに作成したい。 そうすると out_dir に mod.rs を作成して、生成されたモジュールを公開するようにしたい。

use protobuf_codegen_pure::Codegen

fn main() {
    let mut file = fs::File::create("path/to/out/mod.rs")?;
    write!(
        file,
        "{}",
        ["example"]
            .iter()
            .map(|name| format!("pub mod {};\n", name))
            .collect::<String>()
    )?;
    file.flush()
}

このコードで proto ファイルごとに pub mod example; する mod.rs が生成される。

TOP

actix-web でレスポンスを返す

生成されたコードで actix-web のレスポンスを返してみる。

use actix_web::{get, error::ErrorInternalServerError, Responder};
use base64;

#[get("/hello")]
async fn hello() -> impl Responder {
    let mut message = Hello_pb::new();
    message.set_message("hello".to_string());
    message
        .write_to_bytes()
        .map(|bytes| base64::encode_config(bytes, base64::STANDARD))
        .map_err(ErrorInternalServerError)
}

結果を base64::encode_config で、エラーを ErrorInternalServerError で変換している。

追記

最初は actix_web::web::Bytes でエンコードする記事だった。 ただ、受け取る javascript 側のコードは以下のような形にしたい。

Uint8Array.from(atob(raw), (c) => c.charCodeAt(0))

このためにはレスポンスを base64 しないと上手くいかない。 というわけで base64 でエンコードして返すように記事を修正した。

なお、javascript から送信する値も base64 されているので、受け取るときに decode しなければならない。

TOP

まとめ

とりあえず rust でも protobuf できるようになった。 これでフロントエンドと接続できるはず。

TOP

参考資料

TOP