前回でファイルアップができるようになった
その画像をもとに色々できるようなのでまずはサムネイル画像作成をやってみました
やりたい事
firebaseのstorageにファイルがアップされたら
changeイベントを取得してfirebaseのfunctionsを起動して
サムネイル画像を作成する
パッケージの設定
npmのパッケージの設定
/functions/package.json
{ "name": "functions", "description": "Cloud Functions for Firebase", "dependencies": { "firebase-admin": "^4.2.1", "firebase-functions": "^0.5.7", "request": "^2.81.0", "lodash": "^4.17.4", "request-promise": "^4.2.1", "@google-cloud/storage": "^0.4.0", "child-process-promise": "^2.2.0", "mkdirp": "^0.5.1", "mkdirp-promise": "^4.0.0" }, "private": true }
記載が完了したら
npm installのコマンドでインストールする
/functions/index.js
const mkdirp = require('mkdirp-promise'); // Include a Service Account Key to use a Signed URL //const gcs = require('@google-cloud/storage')({keyFilename: 'service-account-credentials.json'}); var gcs = require('@google-cloud/storage')({ projectId: 'angular-study-chat', keyFilename: './service-account-credentials.json' }); const spawn = require('child-process-promise').spawn; const path = require('path'); const os = require('os'); const fs = require('fs'); // Max height and width of the thumbnail in pixels. const THUMB_MAX_HEIGHT = 200; const THUMB_MAX_WIDTH = 200; // Thumbnail prefix added to file names. const THUMB_PREFIX = 'thumb_';
//thumbnail exports.generateThumbnail = functions.storage.object().onChange(event => { // File and directory paths. const filePath = event.data.name; const fileDir = path.dirname(filePath); const fileName = path.basename(filePath); const thumbFilePath = path.normalize(path.join(fileDir, `${THUMB_PREFIX}${fileName}`)); const tempLocalFile = path.join(os.tmpdir(), filePath); const tempLocalDir = path.dirname(tempLocalFile); const tempLocalThumbFile = path.join(os.tmpdir(), thumbFilePath); // console.log('filePath'); // console.log(filePath); // Exit if this is triggered on a file that is not an image. if (!event.data.contentType.startsWith('image/')) { console.log('This is not an image.'); return; } // Exit if the image is already a thumbnail. if (fileName.startsWith(THUMB_PREFIX)) { console.log('Already a Thumbnail.'); return; } // Exit if this is a move or deletion event. if (event.data.resourceState === 'not_exists') { console.log('This is a deletion event.'); return; } // Cloud Storage files. const bucket = gcs.bucket(event.data.bucket); const file = bucket.file(filePath); const thumbFile = bucket.file(thumbFilePath); // Create the temp directory where the storage file will be downloaded. return mkdirp(tempLocalDir).then(() => { // Download file from bucket. return file.download({destination: tempLocalFile}); }).then(() => { console.log('The file has been downloaded to', tempLocalFile); // Generate a thumbnail using ImageMagick. return spawn('convert', [tempLocalFile, '-thumbnail', `${THUMB_MAX_WIDTH}x${THUMB_MAX_HEIGHT}>`, tempLocalThumbFile]); }).then(() => { console.log('Thumbnail created at', tempLocalThumbFile); // Uploading the Thumbnail. return bucket.upload(tempLocalThumbFile, {destination: thumbFilePath}); }).then(() => { console.log('Thumbnail uploaded to Storage at', thumbFilePath); // Once the image has been uploaded delete the local files to free up disk space. fs.unlinkSync(tempLocalFile); fs.unlinkSync(tempLocalThumbFile); // Get the Signed URLs for the thumbnail and original image. const config = { action: 'read', expires: '03-01-2500' }; return Promise.all([ thumbFile.getSignedUrl(config), file.getSignedUrl(config) ]); }).then(results => { console.log('Got Signed URLs.'); const thumbResult = results[0]; const originalResult = results[1]; const thumbFileUrl = thumbResult[0]; const fileUrl = originalResult[0]; // Add the URLs to the Database return admin.database().ref('images').push({path: fileUrl, thumbnail: thumbFileUrl}); }).then(() => console.log('Thumbnail URLs saved to database.')); });
記載が終わったら
firebase deploy --only functions
でデプロイするが
Error: ENOENT: no such file or directory, open 'service-account-credentials.json' at Error (native)
あれ・・・
サンプルに書いてありました
なのでservice-account-credentials.jsonをつくることにしました
firebaseのコンソール画面で
①歯車のマークをクリックする
②ユーザーと権限をクリックする
①サービスアカウント
②サービスアカウントを作成をクリックする
①サービスアカウント名を適当にいれる
②新しい秘密鍵の提供をクリック
③JSONをクリックする
④G Suiteドメイン全体の委任を有効にするをクリック
⑤役割を選択する
⑥ストレージのストレージ管理者
この作成したjsonファイルをservice-account-credentials.jsonにリネームして
/functions/の配下においてもう1度デプロイする
firebase deploy --only functions
画面
ちなみにサービスアカウントをミスをすると以下のエラーがでた
ApiError: Forbidden at new util.ApiError (/user_code/node_modules/@google-cloud/storage/node_modules/@google-cloud/common/src/util.js:107:10) at Object.parseHttpRespMessage (/user_code/node_modules/@google-cloud/storage/node_modules/@google-cloud/common/src/util.js:149:33) at Object.handleResp (/user_code/node_modules/@google-cloud/storage/node_modules/@google-cloud/common/src/util.js:124:18) at Duplexify.<anonymous> (/user_code/node_modules/@google-cloud/storage/src/file.js:711:21) at emitOne (events.js:96:13) at Duplexify.emit (events.js:188:7) at emitOne (events.js:96:13) at DestroyableTransform.emit (events.js:188:7) at emitOne (events.js:96:13) at Request.emit (events.js:188:7) at Request.<anonymous> (/user_code/node_modules/@google-cloud/storage/node_modules/request/request.js:1108:14) at emitOne (events.js:101:20) at Request.emit (events.js:188:7) at IncomingMessage.<anonymous> (/user_code/node_modules/@google-cloud/storage/node_modules/request/request.js:1091:12) at IncomingMessage.g (events.js:292:16) at emitNone (events.js:91:20) at IncomingMessage.emit (events.js:185:7) at endReadableNT (_stream_readable.js:974:12) at _combinedTickCallback (internal/process/next_tick.js:80:11) at process._tickDomainCallback (internal/process/next_tick.js:128:9)
https://github.com/GoogleCloudPlatform/google-cloud-node/issues/1388
このエラーがでたらサービスアカウントにミスがあります