みなさん Git LFS を使用していますか?
わたしは VRChat のアバタープロジェクトをまるまる GitHub へあげているついでに、 Git LFS で 3D モデルやテクスチャーも状態を保存しています。
そこで困るのが、 GitHub のストレージ課金です。 50GB で 60USD/year かかるのですが、これをオンラインストレージで換算すると、微妙に高くない?となります (Wasabi とか 72USD/year で 1TB だしね)。
例えば、ウチのプロジェクトの場合、大きいもので数十 GB くらいあったりするので、それをアップロードするとオシマイです。
そうなるとどんどん高くなって行っちゃうので、個人的には S3 とかにバックアップしたい気持ちがあります。ということで、 Git LFS サーバーを実装してみました。
といっても必要なのは1つだけで、以下のエンドポイントを実装すれば OK です。
POST /objects/batch
わたしは認証機能を付けたかったので、 POST /:user/:repository/objects/batch
として実装していますが、基本的にこのエンドポイントだけ実装してあげれば、 Git LFS サーバーとして必要最低限の機能が動くようになります。
レスポンスも簡単で、次のような型を持つレスポンスを返せば OK です。
type GitLfsObject = { oid: string; size: number; authenticated: boolean; actions: { upload: { href: string; expiresIn?: number; headers?: any; }, download: { href: string; expiresIn?: number; headers?: any; } } }; type GitLfsResponse = { transfer: "basic" | "lfs-standalone-file" | "ssh"; objects: GitLfsObject[]; };
簡単ですね。
Git LFS クライアントからのリクエストは以下の通り。
type GitLfsRequest = { operation: "verify" | "upload" | "download"; transfers: string[]; objects: { oid: string; size: number; }[]; };
基本的には、 operation == upload
のときには、 actions.upload
、 operation == download
のときには actions.download
を返してあげれば問題ありません。
それぞれの中身も、 href
に、それぞれの操作に対応した S3 の Pre-Signed URL を詰め込んで返せば、 Git LFS クライアントが良い感じにしてくれます。
ということで、 Git LFS サーバーの実装についてお話ししてみました。
具体的なコードについて知りたい場合は、下記リポジトリに Vercel にデプロイ可能なコードを置いているので、参考にしてみて下さい。