📘

protocolbuffersをjsで読み込む[gtfsrt]

に公開

ものすごく雑なイントロ

雑記事注意!

gtfs-realtime使いたいなと思っているあなた。
odptとかからdlしてみて、開いてみたら何これという感じになっていて驚いたはずです。そう。これはprotocol buffersで送られてきているためなのです。

結構いろんなところで目にするprotocol buffers。

  • あらかじめ決まり(スキーマ)が決まっている。
  • 決まりに則ってデータが圧縮される。(サーバ)
  • 圧縮されたデータが送られる。
  • 決まりに則って復元する。(クライエント)
    感じなわけです。

詳しい説明は調べるなり、copilotに聞くなりしてください。
とにかく、我々は復元する部分を必要としているわけです。

やってみます

今回はgtfs realtimeをjsonに変換してみましょう。
使うのはprotobufjsとそのcliツールです。
目標は、復号用のスクリプトを生成してもらって簡単に実行することです。

準備

まずは実行環境を整えます。

念のため書いておきます。

  • vscodeをいれましょう。
  • nodejs(v18~)をいれましょう。(brew推奨)

では、復元に欠かせないスキーマの部分を用意します。

https://gtfs.org/documentation/realtime/proto/
スキーマを見るとjsonに似ていますね。

vscodeの左上からターミナルをひらきましょう。
まずは必要なファイルを用意します。

ファイル構成
pbftest
├── gtfs-realtime.proto
├── main.js
└── command.ps1
gtfs-realtime.proto
// 先ほどのリンクからDLしてください。
main.js
// メインのソースコード
const decoder = require('./gtfsrtpbf.js');
var fs = require("fs");

async function main() {
  const response = await fetch('https://api-public.odpt.org/api/v4/gtfs/realtime/toei_odpt_train_vehicle');
  const arrayBuffer = await response.arrayBuffer();
  const uint8Array = new Uint8Array(arrayBuffer);
  console.log(uint8Array);
  const feed = decoder.transit_realtime.FeedMessage.decode(uint8Array);
  const str = JSON.stringify(feed, null, 2);
  fs.writeFileSync("gtfsrt.json", str);
}

main();
command.ps1
# 下準備用
npm install protobufjs protobufjs-cli

npx pbjs `
--target static-module `
--wrap commonjs `
--keep-case `
--out ./gtfsrtpbf.js `
./gtfs-realtime.proto

実行

まず、先ほど説明した変換する部分を用意しましょう。ターミナルにいちいち打つのは面倒なのでスクリプトファイルから実行します。
windowsはターミナルから.\command.ps1で実行します。
macは拡張子を.shに、`\に置き換え、.\command.shで実行してください。

そうすると、フォルダ内にgyfsrtpbf.jsができているはずです。
オプションでライブラリとして使えるように指定しているので、require()を使ってmain.jsで読み込みます。

さいごに、メインのjsを実行しましょう。ターミナルにnode main.jsと打ち込みます。

エラーが出なかったら、カレントディレクトリにgtfsrt.jsonがあるはずです。中身を覗くとvehicleだのなんだのがあって、vehicleの位置とかがわかるはずです。面白くなってきました。
これであなたもgtfsrealtimeに片足を突っ込めました。地図上にバスの位置を表示したりすることもできますがその辺は各自で頑張ってみてください。

https://gtfs.org/ja/documentation/realtime/reference/

そのほか

pbts --out ./gtfsrtpbf.d.ts ./gtfsrtpbf.js

これを実行するとtypescriptの型定義ファイルが得られると思います。

gomi

全然違うけど雰囲気を感じて欲しいの図
// 元のオブジェクト
type obj1 = {"hoge": number, "fuga": {"piyo": number}[]};
const o1: obj1 = {"hoge": 12, "fuga": [{"piyo": 34}, {"piyo": 56}]};
// 圧縮しようとすればこんな感じにできる
type obj2 = [number, (number[])[]];
const o2: obj2 = [12, [[34], [56]]];

p.s. gtfs-flexもやらなくちゃなんだよな。

https://github.com/YamateKyuko/pbftest

Discussion