shared/storageUtil.js (179 lines of code) (raw):

/** * Copyright 2019 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. */ 'use strict'; const { Storage } = require('@google-cloud/storage'); class StorageUtil { constructor(projectId, keyFilename) { this.projectId = projectId; this.keyFilename = keyFilename; const options = {}; if (projectId) { options.projectId = projectId; } if (keyFilename) { options.keyFilename = keyFilename; } this.storage = new Storage(options); } get VERBOSE_MODE() { return process.env.VERBOSE_MODE; } /** * @param {string} bucketName * @param {string} fileName * @param {buffer} contents * @param {Object} options https://cloud.google.com/nodejs/docs/reference/storage/2.5.x/global.html#CreateWriteStreamOptions * Creates a file in Cloud Storage and return true/false; */ async createFile(bucketName, fileName, contents, options) { const bucket = this.storage.bucket(bucketName); const file = bucket.file(fileName); let opt = {}; if (options) { opt = options; } await file.save(contents, opt).catch((err) => { console.warn(err.message); throw err; }); if (this.VERBOSE_MODE) { console.log(`Storage bucket file '${fileName}' created.`); } return true; } /** * @param {} bucketName * @param {} fileName * Delete a file in Cloud Storage and return true/false. */ async deleteFile(bucketName, fileName, ignoreError) { const bucket = this.storage.bucket(bucketName); const file = bucket.file(fileName); return file.delete() .then((response) => { if (this.VERBOSE_MODE) { console.log(`Filename ${fileName} deleted from bucket: ${bucketName}`); } return true; }) .catch((err) => { console.warn(err.message); if (!ignoreError) { throw err; } return false; }); } /* * @param {string} bucketName * Creates a Cloud Storage bucket and returns true. */ async createBucket(bucketName) { return this.storage.createBucket(bucketName); } /** */ async getBuckets() { const [buckets] = await this.storage.getBuckets(); return buckets; } /** * @param {string} bucketName * Delete a Cloud Storage bucket and return true. */ async deleteBucket(bucketName) { return this.storage.bucket(bucketName).delete(); } /** * @param {string} bucketName * Check if a bucket exists and return true/false. */ async bucketExists(bucketName) { const bucket = this.storage.bucket(bucketName); const exists = await bucket.exists().catch((err) => { console.error(err.message); throw err; }); return exists[0]; } /** * @param {string} bucketName * @param {string} fileName * @param {Object} fileMetadata https://googleapis.dev/nodejs/storage/latest/File.html#setMetadata * Updates the file metadata in GCP storage and return true. */ async setFileMetadata(bucketName, fileName, fileMetadata) { const bucket = this.storage.bucket(bucketName); const file = bucket.file(fileName); const results = await file.setMetadata(fileMetadata).catch((err) => { console.warn(err.message); throw err; }); if (this.VERBOSE_MODE) { console.log(`Storage bucket file '${fileName}' metadata updated.`); } return true; } /** * @param {string} bucketName * @param {string} fileName * Check if a file exists and return true/false. */ async fileExists(bucketName, fileName) { const bucket = this.storage.bucket(bucketName); const file = bucket.file(fileName); const exists = await file.exists().catch((err) => { console.error(err.message); throw err; }); return exists[0]; } /** * @param {string} bucketName * @param {string} sourceFile * @param {string} destinationFile * move a file to a new name in the same bucket and return true/false. */ async moveFile(bucketName, sourceFile, destinationFile) { return this.storage .bucket(bucketName) .file(sourceFile) .move(destinationFile) .then((result) => { if (this.VERBOSE_MODE) { console.log(`gs://${bucketName}/${sourceFile} moved to gs://${bucketName}/${destinationFile}.`); } return true; }).catch((err) => { console.warn(err.message); throw err; }); } /** * @param {string} bucketName * @param {string} fileName * Get the metadata of a file and return it. */ async getFileMetadata(bucketName, fileName) { const bucket = this.storage.bucket(bucketName); const file = bucket.file(fileName); const results = await file.getMetadata(); const metadata = results[0]; if (this.VERBOSE_MODE) { console.log(`Storage bucket file '${fileName}' metadata: '${metadata}'.`); } return metadata; } /** * @param {string} bucketName * @param {string} fileName * Check if a file exists and return the content if exists. */ async fetchFileContent(bucketName, fileName) { const bucket = this.storage.bucket(bucketName); const file = bucket.file(fileName); const exists = await this.fileExists(bucketName, fileName); const buf = await file.download(); const content = buf.toString('utf-8'); if (this.VERBOSE_MODE) { console.log(`Fetching the file '${fileName}' content.`); } return content; } /** * @param {string} bucketName * @param {string} fileName * @param {boolean} signed * Returns a (optionally signed) URL for a given file name in Cloud Storage. */ async getUrl(bucketName, fileName, signed) { if (signed === false) { return `https://storage.googleapis.com/${bucketName}/${fileName}`; } else { const bucket = this.storage.bucket(bucketName); const file = bucket.file(fileName); const url = await file.getSignedUrl({ action: 'read', expires: '03-01-2500' }); if (this.VERBOSE_MODE) { console.log(`Signed url created.`); } return url[0]; } } /** * @param {} bucketName * @param {} options */ getBucket(bucketName, options) { return this.storage.bucket(bucketName, options); } /** * @param {} bucketName */ async getAvailableFiles(bucketName, options) { const [files] = await this.storage.bucket(bucketName).getFiles(options); if (this.VERBOSE_MODE) { console.log('Files:'); files.forEach(file => { console.log(file.name); }); } return files.map(f => f.name); } /** * @param {} bucketName * https://googleapis.dev/nodejs/storage/latest/Iam.html#getPolicy * https://github.com/googleapis/nodejs-storage/blob/master/samples/viewBucketIamMembers.js */ async getBucketIamPolicy(bucketName) { const bucket = this.storage.bucket(bucketName); return bucket.iam.getPolicy({ requestedPolicyVersion: 3 }) .then(data => { const policy = data[0]; const apiResponse = data[1]; return policy; }).catch((err) => { console.error(err); throw err; }); } /** * @param {} bucketName * @param {} policy * https://googleapis.dev/nodejs/storage/latest/Iam.html#setPolicy * https://github.com/googleapis/nodejs-storage/blob/master/samples/addBucketIamMember.js */ async setBucketIamPolicy(bucketName, policy) { const bucket = this.storage.bucket(bucketName); return bucket.iam.setPolicy(policy).then(data => { const policy = data[0]; const apiResponse = data[1]; return policy; }).catch((err) => { console.error(err); throw err; }); } } module.exports = StorageUtil;