protocolbuffersをjsで読み込む[gtfsrt]
ものすごく雑なイントロ
雑記事注意!
gtfs-realtime
使いたいなと思っているあなた。
odptとかからdlしてみて、開いてみたら何これという感じになっていて驚いたはずです。そう。これはprotocol buffers
で送られてきているためなのです。
結構いろんなところで目にするprotocol buffers。
- あらかじめ決まり(スキーマ)が決まっている。
- 決まりに則ってデータが圧縮される。(サーバ)
- 圧縮されたデータが送られる。
- 決まりに則って復元する。(クライエント)
感じなわけです。
詳しい説明は調べるなり、copilotに聞くなりしてください。
とにかく、我々は復元する部分を必要としているわけです。
やってみます
今回はgtfs realtime
をjsonに変換してみましょう。
使うのはprotobufjsとそのcliツールです。
目標は、復号用のスクリプトを生成してもらって簡単に実行することです。
準備
まずは実行環境を整えます。
念のため書いておきます。
- vscodeをいれましょう。
- nodejs(v18~)をいれましょう。(brew推奨)
では、復元に欠かせないスキーマの部分を用意します。
スキーマを見るとjsonに似ていますね。
vscodeの左上からターミナルをひらきましょう。
まずは必要なファイルを用意します。
pbftest
├── gtfs-realtime.proto
├── main.js
└── command.ps1
// 先ほどのリンクからDLしてください。
// メインのソースコード
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();
# 下準備用
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に片足を突っ込めました。地図上にバスの位置を表示したりすることもできますがその辺は各自で頑張ってみてください。
そのほか
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もやらなくちゃなんだよな。
Discussion