services/thumbnails/nodejs/index.js (58 lines of code) (raw):
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
const express = require('express');
const imageMagick = require('imagemagick');
const Promise = require("bluebird");
const path = require('path');
const {Storage} = require('@google-cloud/storage');
const Firestore = require('@google-cloud/firestore');
const app = express();
app.use(express.json());
app.post('/', async (req, res) => {
try {
const pubSubMessage = req.body;
console.log(`PubSub message: ${JSON.stringify(pubSubMessage)}`);
const eventType = pubSubMessage.message.attributes.eventType;
const fileEvent = JSON.parse(Buffer.from(pubSubMessage.message.data, 'base64').toString().trim());
if (eventType != 'OBJECT_FINALIZE')
{
console.log(`Event type ${eventType} is not OBJECT_FINALIZE. Skipping file: ${fileEvent.name}`);
res.status(204).send(`File ${fileEvent.name} skipped`);
return;
}
console.log(`Base 64 decoded file event: ${JSON.stringify(fileEvent)}`);
console.log(`Received thumbnail request for file ${fileEvent.name} from bucket ${fileEvent.bucket}`);
const storage = new Storage();
const bucket = storage.bucket(fileEvent.bucket);
const thumbBucket = storage.bucket(process.env.BUCKET_THUMBNAILS);
const originalFile = path.resolve('/tmp/original', fileEvent.name);
const thumbFile = path.resolve('/tmp/thumbnail', fileEvent.name);
await bucket.file(fileEvent.name).download({
destination: originalFile
});
console.log(`Downloaded picture into ${originalFile}`);
const resizeCrop = Promise.promisify(imageMagick.crop);
await resizeCrop({
srcPath: originalFile,
dstPath: thumbFile,
width: 400,
height: 400
});
console.log(`Created local thumbnail in ${thumbFile}`);
await thumbBucket.upload(thumbFile);
console.log(`Uploaded thumbnail to Cloud Storage bucket ${process.env.BUCKET_THUMBNAILS}`);
const pictureStore = new Firestore().collection('pictures');
const doc = pictureStore.doc(fileEvent.name);
await doc.set({
thumbnail: true
}, {merge: true});
console.log(`Updated Firestore about thumbnail creation for ${fileEvent.name}`);
res.status(204).send(`${fileEvent.name} processed`);
} catch (err) {
console.log(`Error: creating the thumbnail: ${err}`);
console.error(err);
res.status(500).send(err);
}
});
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
console.log(`Started thumbnail generator on port ${PORT}`);
});