Rust で GoogleDrive を操作する

2025/03/08に公開

Rust でGoogle APIログイン

Google API に接続する方法は大きく分けて2種類あります。

  1. OAuth認証 - 個人ユーザーの権限で操作(今回使用)
  2. サービスアカウント - バックグラウンド処理などロボット用の権限

今回は一般的なユースケースであるOAuth認証を使用します。

Google Cloud でプロジェクトを作成

まずは Rust プログラムから Google Drive API にアクセスできるようにしましょう。 client_secret.json というプログラムから Google Drive API にアクセスするために必要な JSON ファイルをダウンロードをするまでを行います。

以下画像ペタペタで長いのでわからん人は展開して読んでください。また、内容は 2025年 3月現在のものです。

Google Cloudeからclient_secret.jsonを取得するまで

Google Cloud にアクセスし(※ Googleにはログインしておいてください)、「プロジェクトの選択」→「新しいプロジェクト」を押します。

なお、今回は新規に作りますが、上記画面の様に「API Project」 というのがあるかもしれません。これは、自動的に作られるプロジェクトのようです。

新しいプロジェクトの画面に移動したら、適当にプロジェクト名を決めて、「作成」を押してください。

私は個人でやっているので「組織なし」にしていますが、会社などでやる場合は組織を選択するとよいでしょう。

再び元の画面に戻ってきてしばらくするとプロジェクトが作られます。

「プロジェクトの選択」→「今作ったプロジェクト名」を押して、プロジェクトに入ります。

ハンバーガーメニューを押して「APIとサービス」→「ライブラリ」を選択します。

検索ボックスで 「Google Drive API」で検索をかけ、 Google Drive API を見つけ、クリックします。

Google Drive API の画面に移動したら「有効にする」を押します。

こんな感じの画面になるので、「認証情報(画像で黄色いところ)」をクリックします。(なお、実際には黄色くないです)

何も認証情報が作られていないので、「+認証情報を作成」から OAuthクライアントIDを作成します。(なお、実際には黄色くないです)


で、なんか出てくるので「同意画面の構成」を押して、なんか出てくるので「開始」を押します。

アプリ名を適当に入力し、サポートメールを設定し「次へ」を押します。私のアドレスは非公開(黒塗り)ですよ。

会社専用のアプリなど「組織」としてやっている場合は「内部」を選択できます。私はただの個人なので外部しか選べませんので、「外部」を選びます。

連絡先のメアドを設定します。サポートメールと何が違うんだ?よくわからん。

最後に同意して「続行」を押し、「作成」を押します。

なんかこんな画面になるので「OAUTH クライアントを作成(画像で黄色いところ)」押します。(なお、実際には黄色くないです)

適当にアプリケーションの種類と名前を設定して「作成」を押します。

こんな感じでクライアントが作られるので図中の「↓」ボタン(図で青いアイコン)を押します。(なお、実際には青くないです)

ポップアップする画面で 「JSONをダウンロード」を押し、 client_secret.json をダウンロードします。

ダウンロードした JSON ファイルは実際にプログラムを動かすときに必要になります。

続いて、「外部」を選んだ場合はクライアントを使えるアカウントを指定します。

※ 「内部」を選んだ場合は不要です。

画面の左にある「対象」をクリックします。

テストユーザーの「+ADD USERS」から自分のGoogleアカウントを登録しましょう。追加すると、画像で「表示する行がありません」になっている場所に自分のアドレスが表示されます。

OAuth認証でログイン

Google Drive APIをRustで利用するには、google-drive3というクレートが提供されています。

まず最初にすべきことはログインです。今回は OAuth 認証を行います。該当コードはこちら。

https://github.com/nodamushi/zenn-program/blob/d2ee5ce30b3476570a3a11c3e191d8d7f7d559c9/src/rust/google_drive_study/google_drive/src/lib.rs#L284-L304

read_application_secret で先に保存しておいた client_secret.json を読み込みます。
OAuth ではユーザーがログインして認証しなければプログラムが使えませんが、毎回ログインするのは面倒です。そこで、 persist_tokens_to_disk でファイルにトークンを保存しておきます。

flow_delegate を使うと、どの様にログインURLを表示するかを変更できます。例えば open クレート を使ってブラウザで表示するようにしたのがこちら。

https://github.com/nodamushi/zenn-program/blob/137f11d5bacd2a723f12b9d9ec9f32df05fd099f/src/rust/google_drive_study/src/main.rs#L7-L25

こんな感じで自動的にブラウザが開きます。

Google Driveのフォルダ内のファイル一覧

Google Drive API ではフォルダ内のファイルの一覧を取るには Method: files.list を使います。

files.list はフォルダ内の一覧を得るためのものではなく、どちらかというと検索をするための機能で、どの様な検索クエリを投げるかで取得するファイルの一覧が変わります。今回は files.list でフォルダ内のファイル一覧を得たいので 'Folder ID' in parents というクエリを投げます。

他のクエリについてはファイルやフォルダを検索する を参照してください。

files.list は数が多すぎると一度で全部の結果は返してくれませんので、すべてを得るには何度か繰り返す必要があります。

そして、Google Drive API は基本的にそのままでは情報を返してはくれません。何を必要とするか fields で指定する必要があります。とりあえず、今回はファイル情報として「Drive ID,ファイル名、ファイルタイプ、修正時刻、ダウンロード可能か」の情報を取得します。

  • nextPageToken: 繰り返しに必要
  • files: Fileの情報
    • id: DriveID
    • name: ファイル名
    • mimeType: ファイルの種類
    • modifiedTime: 修正時刻
    • capabilities
      • canDownload: ダウンロード可能か?

上記は "nextPageToken, files(id,name,mimeType,modifiedTime,capabilities(canDownload))" と書きます。

また実行するときには add_scopeadd_scopes必要なスコープを指定してやります。 今回はファイルのダウンロードまでなので drive.readonly があれば十分です。ファイルの一覧を得るだけなら drive.meta.readonly でも良いです。

スコープごとにユーザーが許可しないといけないので、プログラム全体で必要な権限を毎回 add_scopes にいれるとよいでしょう。

というわけで、全体的なコードは以下のようになります。

https://github.com/nodamushi/zenn-program/blob/3a536c70a7b32c322a967bafde3c471973b4b3a2/src/rust/google_drive_study/google_drive/src/lib.rs#L335-L379

Google Driveからファイルをダウロード

Rust力が低くてめっちゃ苦しんだ。

ファイルのダウンロードは Method: files.getalt = media を付与して実行するだけです。スコープは drive.readonly があれば十分です。

https://github.com/nodamushi/zenn-program/blob/3a536c70a7b32c322a967bafde3c471973b4b3a2/src/rust/google_drive_study/google_drive/src/lib.rs#L488-L496

で、上記の rsp からファイルの内容を取得していきますが、この段階ではまだファイルはダウンロードされていません。それどころか async な関数すらなく poll_frame とかいうなんだかよくわかんない関数 しかありません。サンプルコードも全然見つからねぇし、どないすりゃええねん、ってなりました。

結論としては、以下のように poll_fnContext を受け取って、ピン留めして使います。

let frame = std::future::poll_fn(|cx| {
    let body = std::pin::Pin::new(rsp.body_mut());
    body.poll_frame(cx)
}).await;

もちろん、一発で全部のデータが取得できるわけではないのでストリームの終わりまでループして取得します。というわけで、全体としてはこんな感じ。

https://github.com/nodamushi/zenn-program/blob/3a536c70a7b32c322a967bafde3c471973b4b3a2/src/rust/google_drive_study/google_drive/src/lib.rs#L515-L531

まとめ

今回作ったコードはこちら

Rust で Google Drive API を操作しようと思ったら割と Rust の低レベルな知識が必要とされました。
もっとサクッとダウンロードできたらいいのにね。

最初はなんか OAuth のところのコードビルドすらできなかったり(なんかいつの間にかビルドできるようになった)、結構つまりまくりました。

皆さんの手助けになれば幸いです。

Discussion