Initial commit of Google Cloud Storage File Adapter

This commit is contained in:
Mike McDonald
2016-02-27 16:33:34 -08:00
parent db9b72b147
commit 2520e7b6c6
3 changed files with 105 additions and 6 deletions

View File

@@ -26,6 +26,7 @@
"commander": "^2.9.0",
"deepcopy": "^0.6.1",
"express": "^4.13.4",
"gcloud": "^0.28.0",
"mime": "^1.3.4",
"mongodb": "~2.1.0",
"multer": "^1.1.0",

View File

@@ -0,0 +1,96 @@
// GCSAdapter
// Store Parse Files in Google Cloud Storage: https://cloud.google.com/storage
import * as gcloud from 'gcloud';
import { FilesAdapter } from './FilesAdapter';
export class GCSAdapter extends FilesAdapter {
// GCS Project ID and the name of a corresponding Keyfile are required.
// See https://googlecloudplatform.github.io/gcloud-node/#/docs/master/guides/authentication
// for more details.
constructor(
projectId,
keyFilename,
bucket,
{ bucketPrefix = '',
directAccess = false } = {}
) {
super();
this._bucket = bucket;
this._bucketPrefix = bucketPrefix;
this._directAccess = directAccess;
let gcsOptions = {
projectId: projectId,
keyFilename: keyFilename
};
this._gcsClient = new gcloud.storage(gcsOptions);
}
// For a given config object, filename, and data, store a file in GCS.
// Resolves the promise or fails with an error.
createFile(config, filename, data) {
return new Promise((resolve, reject) => {
let file = this._gcsClient.bucket(this._bucket).file(this._bucketPrefix + filename);
// gcloud supports upload(file) not upload(bytes), so we need to stream.
var uploadStream = file.createWriteStream(options);
uploadStream.on('error', (err) => {
return reject(err);
}).on('finish', () => {
// Second call to set public read ACL after object is uploaded.
if (this._directAccess) {
file.makePublic((err, res) => {
if (err !== null) {
return reject(err);
}
resolve();
});
}
resolve();
});
uploadStream.write(data);
uploadStream.end();
});
}
// Deletes a file with the given file name.
// Returns a promise that succeeds with the delete response, or fails with an error.
deleteFile(config, filename) {
return new Promise((resolve, reject) => {
let file = this._gcsClient.bucket(this._bucket).file(this._bucketPrefix + filename);
file.delete((err, res) => {
if(err !== null) {
return reject(err);
}
resolve(res);
});
});
}
// Search for and return a file if found by filename.
// Returns a promise that succeeds with the buffer result from GCS, or fails with an error.
getFileData(config, filename) {
return new Promise((resolve, reject) => {
let file = this._gcsClient.bucket(this._bucket).file(this._bucketPrefix + filename);
file.download((err, data) => {
if (err !== null) {
return reject(err);
}
resolve(data);
});
});
}
// Generates and returns the location of a file stored in GCS for the given request and filename.
// The location is the direct GCS link if the option is set,
// otherwise we serve the file through parse-server.
getFileLocation(config, filename) {
if (this._directAccess) {
return `https://${this._bucket}.storage.googleapis.com/${this._bucketPrefix + filename}`;
}
return (config.mount + '/files/' + config.applicationId + '/' + encodeURIComponent(filename));
}
}
export default GCSAdapter;

View File

@@ -14,6 +14,7 @@ import cache from './cache';
import PromiseRouter from './PromiseRouter';
import { GridStoreAdapter } from './Adapters/Files/GridStoreAdapter';
import { S3Adapter } from './Adapters/Files/S3Adapter';
import { GCSAdapter } from './Adapters/Files/GCSAdapter';
import { FilesController } from './Controllers/FilesController';
import ParsePushAdapter from './Adapters/Push/ParsePushAdapter';
@@ -91,11 +92,11 @@ function ParseServer({
serverURL = requiredParameter('You must provide a serverURL!'),
maxUploadSize = '20mb'
}) {
// Initialize the node client SDK automatically
Parse.initialize(appId, javascriptKey || 'unused', masterKey);
Parse.serverURL = serverURL;
if (databaseAdapter) {
DatabaseAdapter.setAdapter(databaseAdapter);
}
@@ -103,7 +104,7 @@ function ParseServer({
if (databaseURI) {
DatabaseAdapter.setAppDatabaseURI(appId, databaseURI);
}
if (cloud) {
addParseCloud();
if (typeof cloud === 'function') {
@@ -125,7 +126,7 @@ function ParseServer({
const pushController = new PushController(pushControllerAdapter);
const loggerController = new LoggerController(loggerControllerAdapter);
const hooksController = new HooksController(appId, collectionPrefix);
cache.apps[appId] = {
masterKey: masterKey,
collectionPrefix: collectionPrefix,
@@ -185,7 +186,7 @@ function ParseServer({
if (process.env.PARSE_EXPERIMENTAL_CONFIG_ENABLED || process.env.TESTING) {
routers.push(require('./global_config'));
}
if (process.env.PARSE_EXPERIMENTAL_HOOKS_ENABLED || process.env.TESTING) {
routers.push(new HooksRouter());
}
@@ -229,5 +230,6 @@ function getClassName(parseClass) {
module.exports = {
ParseServer: ParseServer,
S3Adapter: S3Adapter
S3Adapter: S3Adapter,
GCSAdapter: GCSAdapter
};