Google Cloud APIの中には、gs://[bucket]/[path]
の形式になっているCloud StorageのURLを与えることができるものがある。今回はGoogleドライブに入っているファイルをCloud Storageにコピーしてgs://
のURLとして使えるようにしたかった。
streamをうまく使うことで、一時ファイルを作らずにコピーすることができた。
準備
以下のパッケージをインストールしておく。
$ npm i googleapis @google-cloud/storage
ドライブ用にGoogle APIのOAuthクライアントIDを作成する。APIとサービスの認証情報から[OAuth クライアント ID の作成]で作成できる。コマンドラインツールの場合は[その他]を選んで作成する。JSONをダウンロードしておく。
Cloud Storage用にサービスアカウントキーを発行して、これもJSONをダウンロードしておく。
Googleドライブの認証
ドライブ公式のクイックスタートをまとめ直したクラスを作った。
https://gist.github.com/iseebi/4d21bf68c79bc020ea3515693676a35f
コピー関数
こんな感じの関数を書いた。
import{Bucket,Storage}from"@google-cloud/storage";import{Readable}from"stream";importDrive=drive_v3.Drive;asyncfunctioncopyDriveToStorage(drive:Drive,bucket:Bucket,driveFileId:string,uploadFileName:string){constmeta=awaitdrive.files.get({fileId:driveFileId,supportsTeamDrives:true,fields:'mimeType'});constmedia=awaitdrive.files.get({fileId:driveFileId,supportsTeamDrives:true,alt:'media'},{responseType:'stream'});constuploadFile=bucket.file(uploadFileName);awaitnewPromise<void>((resolve,reject)=>{constdownloadStream=media.dataasReadable;constuploadStream=uploadFile.createWriteStream({metadata:{cacheControl:'no-cache',contentType:meta.data.mimeType,}});downloadStream.pipe(uploadStream);downloadStream.on('error',reject);uploadStream.on('error',reject);uploadStream.on('finish',resolve);});}
ポイントはこのあたり。
drive.file.get
のparamsにalt: 'media'
、optionsにresponseType: 'stream'
を指定- その戻り値の
data
をReadableにキャストする → 読み込み用のストリーム bucket.file
でcreateWriteStream
→ 書き込み用のストリーム- 読み込み用のストリームから、書き込み用のストリームに
pipe
する - 書き込み用のストリームがfinishしたら完了、どちらかのストリームがエラーを返したらreject
今回実際に使ったものでは、mimeTypeを事前に絞り込んでいたので、metaの取得はせずにハードコーディングした。
呼び出し
こんな感じで使う。
import{Bucket,Storage}from"@google-cloud/storage";import{Authenticator}from"./authenticator";import{google}from"googleapis";constauth=awaitauthenticator.authenticateAsync();constdrive=google.drive({version:'v3',auth});conststorage=newStorage({projectID:'00000000000',keyFilename:'service_account.json'});constbucket=storage.bucket('my-bucket-name');constfileID='......';constdestination='filename';awaitcopyDriveToStorage(drive,bucket,fileID,destination);