Open8

Google CloudとGoogle Driveの連携

tomoyukiktomoyukik

Google Drive上のファイルのパスを取得するコード

SCOPES = ['https://www.googleapis.com/auth/drive.metadata.readonly']


def dig_parents(id, creds) -> list[str]:
    service = build('drive', 'v3', credentials=creds)

    item = service.files().get(fileId=id, fields="id,name,kind,parents").execute()
    name = item.get("name")
    parents = item.get("parents")

    if parents is None:
        return [(id, name)]

    if len(parents) != 1:
        raise Exception("Unpexpected parents count.")
    
    parent_id = parents[0]
    return dig_parents(parent_id, creds) + [(id, name)]

if __name__ == "__main__":
    file_id = sys.argv[1]

    flow = InstalledAppFlow.from_client_secrets_file('credentials.json', SCOPES)
    creds = flow.run_local_server(port=0)
    parents = dig_parents(file_id, creds)
    print(parents)
tomoyukiktomoyukik

Google Driveの変更を検知する

以下を作成する。

  1. 受信用URL (Webhook call back receiver)
  2. 監視対象のリソースエンドポイントのチャネル
  • ファイル単位や変更全体などの単位でリソースを指定する

チャネルの作成

https://www.googleapis.com/{apiName}/{apiVersion}/{resourcePath}/watch

の形式に従ってURLを組み立て、POSTリクエストのボディで作成するチャネルを指定する。

変更全体を監視する場合は

https://www.googleapis.com/drive/v3/changes/watch
tomoyukiktomoyukik

Cloud FunctionでGoogle Driveの更新通知を受け取る場合

  1. CloudFuncitonをデプロイ
  2. チャネルを作成

1. CloudFuncitonをデプロイ

例えば下記。
ドキュメントに記載があるように、通知は POST で送信され、ボディは空になっている。
changesリソースを監視する場合、X-Goog-Resource-Stateは常にchangesとなり、どういう変更がされたかまでは特定できない。

import functions_framework

@functions_framework.http
def hello_http(request):
    print(request.headers)

     return 'OK'

2. チャネルを作成

Pythonなら下記でできる。

def register_channel2(creds):
    service = build('drive', 'v3', credentials=creds)

    # start_page_tokenの取得
    response = service.changes().getStartPageToken().execute()
    start_page_token = response.get("startPageToken")
    if start_page_token is None:
        raise Exception("Invalid start page token")

    # チャネルの登録
    response = service.changes().watch(
        pageToken=start_page_token,
        body={
            "address": "{CloudFunctionのURL}",
            "type": "web_hook", # web_hook を指定
            "id": str(uuid4()), # 任意の一意な文字列
        }
    ).execute()

    print(response)
tomoyukiktomoyukik
  • changesのwatchでは変更があったことしかわからないので、changes.listで何の変更があったかを確認する必要がある。
  • Cloud Functionsで確認するためには、Cloud FunctionsにアタッチされているSAにGoogle Drive上の対象のフォルダを共有しておく必要がある。
  • 共有されていないフォルダの変更でもpush通知がされてしまうので注意が必要
  • changes.listをしても何の変更がされたかまではわからない

参考: https://qiita.com/kccs_kai-morita/items/6c5844dc78ce630ebb94