Rustで初めてツールを作ったときのあれこれ
はじめに
Rustの勉強がてら何かツールを作りたいと思いました。
ちょうどその頃、tcpdumpでパケットを眺めるとき「tcpdump起動後にパケットフィルターできないの不便だな」と思ってたのでそれを解決するツールを作ることにしました。
で、出来上がったのがこちらwirewhaleです。イメージとしてはTUIで動くWiresharkを目指しました。
全体像
アプリケーションは主に3つのスレッド(非同期タスク)があります。まずはmainスレッドにてキーボードイベントを取得し、Appの内部状態を操作しています。次に標準入力からpcapフォーマットのデータを読み取りパケットデータとしてApp内に保存する非同期タスクがあります。標準入力からの読み込みはasync_stdのStdinを利用しているので非同期タスクとして実行(async_std::task::spawn)しています。最後にターミナルに定期的に情報を出力するスレッドがあります。ここの出力はcrosstermとtui-rsを利用しており、非同期タスクとすることができなかったのでスレッドとして実行(async_std::task::spawn_blocking)しています。
CI/CD(GithubActions)
ツールを作成にするにあたってのCI/CDは今回初めてGithubActionsを使ってみました。
まずはCIです。
CIで行うことはリントとフォーマットとテストです。actions-rs/toolchainでtoolをインストールしてactions-rs/cargoで実行するだけなのでとても簡単にできました。次にCDです
バージョンタグ(vX.X.X)が打たれた時にトリガーされ、リリースを作成してビルドしてアップロードするようにしました。GithubActionsではクロスコンパイルせずに複数ターゲットに対してビルドできるんですね。ただ、アップロードする生成物のアーカイブを作成する処理がシェルスクリプトで書かなければいけないのがなんだかなぁという感じです。cargo-release
GithubActionsによってバージョンタグを打つとビルドされるようになりましたが、手動でバージョンタグを打つとgitでのバージョンとCargo.tomlに記載されているバージョンに差異が生じる可能性があります。clapによって--versionで表示されるバージョンやcrate.ioで公開されるバージョンはCargo.tomlに記載されいるバージョンなのでここの差異はなくしたいところです。
cargo-releaseを使えばCargo.tomlのバージョンをインクリメントしつつバージョンタグを打つということを行ってくれるのでリリース作業はcargo-releaseを使えば差異はなくなります。また、cargo-releaseを使うとcrate.ioにpublishもできます。
ちなみにclapを使うと下記のような構造体を作ってmain関数でparseメソッドを呼ぶだけで--versionオプションが実装されます
おわりに
はっきり言って時間をかけて作った割にツールの完成度はイマイチです。まだまだ問題は山積みです。
- パケット数が多いとフィルタに時間がかかる
- フィルタがただの文字列一致しかしてない
- 対応しているプロトコルが少ない
ただ、作るうえでいろいろなことを学ぶことができたので目的は達成しました。
Discussion