ParseServer is a class

This commit is contained in:
Florent Vilmart
2016-03-11 10:01:44 -05:00
parent fb57d91b83
commit 260cc21b67
2 changed files with 254 additions and 180 deletions

View File

@@ -79,187 +79,205 @@ addParseCloud();
// "javascriptKey": optional key from Parse dashboard
// "push": optional key from configure push
function ParseServer({
appId = requiredParameter('You must provide an appId!'),
masterKey = requiredParameter('You must provide a masterKey!'),
appName,
databaseAdapter,
filesAdapter,
push,
loggerAdapter,
databaseURI = DatabaseAdapter.defaultDatabaseURI,
databaseOptions,
cloud,
collectionPrefix = '',
clientKey,
javascriptKey,
dotNetKey,
restAPIKey,
fileKey = 'invalid-file-key',
facebookAppIds = [],
enableAnonymousUsers = true,
allowClientClassCreation = true,
oauth = {},
serverURL = requiredParameter('You must provide a serverURL!'),
maxUploadSize = '20mb',
verifyUserEmails = false,
emailAdapter,
publicServerURL,
customPages = {
invalidLink: undefined,
verifyEmailSuccess: undefined,
choosePassword: undefined,
passwordResetSuccess: undefined
},
liveQuery = {}
}) {
setFeature('serverVersion', parseServerPackage.version);
// Initialize the node client SDK automatically
Parse.initialize(appId, javascriptKey || 'unused', masterKey);
Parse.serverURL = serverURL;
export default class ParseServer {
if (databaseAdapter) {
DatabaseAdapter.setAdapter(databaseAdapter);
}
constructor({
appId = requiredParameter('You must provide an appId!'),
masterKey = requiredParameter('You must provide a masterKey!'),
appName,
databaseAdapter,
filesAdapter,
push,
loggerAdapter,
databaseURI = DatabaseAdapter.defaultDatabaseURI,
databaseOptions,
cloud,
collectionPrefix = '',
clientKey,
javascriptKey,
dotNetKey,
restAPIKey,
fileKey = 'invalid-file-key',
facebookAppIds = [],
enableAnonymousUsers = true,
allowClientClassCreation = true,
oauth = {},
serverURL = requiredParameter('You must provide a serverURL!'),
maxUploadSize = '20mb',
verifyUserEmails = false,
emailAdapter,
publicServerURL,
customPages = {
invalidLink: undefined,
verifyEmailSuccess: undefined,
choosePassword: undefined,
passwordResetSuccess: undefined
},
liveQuery = {}
}) {
setFeature('serverVersion', parseServerPackage.version);
// Initialize the node client SDK automatically
Parse.initialize(appId, javascriptKey || 'unused', masterKey);
Parse.serverURL = serverURL;
if (databaseURI) {
DatabaseAdapter.setAppDatabaseURI(appId, databaseURI);
}
if (databaseOptions) {
DatabaseAdapter.setAppDatabaseOptions(appId, databaseOptions);
}
if (cloud) {
addParseCloud();
if (typeof cloud === 'function') {
cloud(Parse)
} else if (typeof cloud === 'string') {
require(cloud);
} else {
throw "argument 'cloud' must either be a string or a function";
if (databaseAdapter) {
DatabaseAdapter.setAdapter(databaseAdapter);
}
}
const filesControllerAdapter = loadAdapter(filesAdapter, () => {
return new GridStoreAdapter(databaseURI);
});
// Pass the push options too as it works with the default
const pushControllerAdapter = loadAdapter(push && push.adapter, ParsePushAdapter, push);
const loggerControllerAdapter = loadAdapter(loggerAdapter, FileLoggerAdapter);
const emailControllerAdapter = loadAdapter(emailAdapter);
// We pass the options and the base class for the adatper,
// Note that passing an instance would work too
const filesController = new FilesController(filesControllerAdapter, appId);
const pushController = new PushController(pushControllerAdapter, appId);
const loggerController = new LoggerController(loggerControllerAdapter, appId);
const hooksController = new HooksController(appId, collectionPrefix);
const userController = new UserController(emailControllerAdapter, appId, { verifyUserEmails });
const liveQueryController = new LiveQueryController(liveQuery);
if (databaseOptions) {
DatabaseAdapter.setAppDatabaseOptions(appId, databaseOptions);
}
if (databaseURI) {
DatabaseAdapter.setAppDatabaseURI(appId, databaseURI);
}
cache.apps.set(appId, {
masterKey: masterKey,
serverURL: serverURL,
collectionPrefix: collectionPrefix,
clientKey: clientKey,
javascriptKey: javascriptKey,
dotNetKey: dotNetKey,
restAPIKey: restAPIKey,
fileKey: fileKey,
facebookAppIds: facebookAppIds,
filesController: filesController,
pushController: pushController,
loggerController: loggerController,
hooksController: hooksController,
userController: userController,
verifyUserEmails: verifyUserEmails,
allowClientClassCreation: allowClientClassCreation,
authDataManager: authDataManager(oauth, enableAnonymousUsers),
appName: appName,
publicServerURL: publicServerURL,
customPages: customPages,
liveQueryController: liveQueryController
});
// To maintain compatibility. TODO: Remove in some version that breaks backwards compatability
if (process.env.FACEBOOK_APP_ID) {
cache.apps.get(appId)['facebookAppIds'].push(process.env.FACEBOOK_APP_ID);
}
Config.validate(cache.apps.get(appId));
// This app serves the Parse API directly.
// It's the equivalent of https://api.parse.com/1 in the hosted Parse API.
var api = express();
//api.use("/apps", express.static(__dirname + "/public"));
// File handling needs to be before default middlewares are applied
api.use('/', middlewares.allowCrossDomain, new FilesRouter().getExpressRouter({
maxUploadSize: maxUploadSize
}));
api.use('/', bodyParser.urlencoded({extended: false}), new PublicAPIRouter().expressApp());
// TODO: separate this from the regular ParseServer object
if (process.env.TESTING == 1) {
api.use('/', require('./testing-routes').router);
}
api.use(bodyParser.json({ 'type': '*/*' , limit: maxUploadSize }));
api.use(middlewares.allowCrossDomain);
api.use(middlewares.allowMethodOverride);
api.use(middlewares.handleParseHeaders);
let routers = [
new ClassesRouter(),
new UsersRouter(),
new SessionsRouter(),
new RolesRouter(),
new AnalyticsRouter(),
new InstallationsRouter(),
new FunctionsRouter(),
new SchemasRouter(),
new PushRouter(),
new LogsRouter(),
new IAPValidationRouter(),
new FeaturesRouter(),
];
if (process.env.PARSE_EXPERIMENTAL_CONFIG_ENABLED || process.env.TESTING) {
routers.push(new GlobalConfigRouter());
}
if (process.env.PARSE_EXPERIMENTAL_HOOKS_ENABLED || process.env.TESTING) {
routers.push(new HooksRouter());
}
let routes = routers.reduce((memo, router) => {
return memo.concat(router.routes);
}, []);
let appRouter = new PromiseRouter(routes);
batch.mountOnto(appRouter);
api.use(appRouter.expressApp());
api.use(middlewares.handleParseErrors);
//This causes tests to spew some useless warnings, so disable in test
if (!process.env.TESTING) {
process.on('uncaughtException', (err) => {
if( err.code === "EADDRINUSE" ) { // user-friendly message for this common error
console.log(`Unable to listen on port ${err.port}. The port is already in use.`);
process.exit(0);
}
else {
throw err;
if (cloud) {
addParseCloud();
if (typeof cloud === 'function') {
cloud(Parse)
} else if (typeof cloud === 'string') {
require(cloud);
} else {
throw "argument 'cloud' must either be a string or a function";
}
}
const filesControllerAdapter = loadAdapter(filesAdapter, () => {
return new GridStoreAdapter(databaseURI);
});
}
hooksController.load();
// Pass the push options too as it works with the default
const pushControllerAdapter = loadAdapter(push && push.adapter, ParsePushAdapter, push);
const loggerControllerAdapter = loadAdapter(loggerAdapter, FileLoggerAdapter);
const emailControllerAdapter = loadAdapter(emailAdapter);
// We pass the options and the base class for the adatper,
// Note that passing an instance would work too
const filesController = new FilesController(filesControllerAdapter, appId);
const pushController = new PushController(pushControllerAdapter, appId);
const loggerController = new LoggerController(loggerControllerAdapter, appId);
const hooksController = new HooksController(appId, collectionPrefix);
const userController = new UserController(emailControllerAdapter, appId, { verifyUserEmails });
const liveQueryController = new LiveQueryController(liveQuery);
return api;
cache.apps.set(appId, {
masterKey: masterKey,
serverURL: serverURL,
collectionPrefix: collectionPrefix,
clientKey: clientKey,
javascriptKey: javascriptKey,
dotNetKey: dotNetKey,
restAPIKey: restAPIKey,
fileKey: fileKey,
facebookAppIds: facebookAppIds,
filesController: filesController,
pushController: pushController,
loggerController: loggerController,
hooksController: hooksController,
userController: userController,
verifyUserEmails: verifyUserEmails,
allowClientClassCreation: allowClientClassCreation,
authDataManager: authDataManager(oauth, enableAnonymousUsers),
appName: appName,
publicServerURL: publicServerURL,
customPages: customPages,
maxUploadSize: maxUploadSize,
liveQueryController: liveQueryController
});
// To maintain compatibility. TODO: Remove in some version that breaks backwards compatability
if (process.env.FACEBOOK_APP_ID) {
cache.apps.get(appId)['facebookAppIds'].push(process.env.FACEBOOK_APP_ID);
}
Config.validate(cache.apps.get(appId));
this.config = cache.apps.get(appId);
hooksController.load();
}
get app() {
return ParseServer.app(this.config);
}
static app({maxUploadSize = '20mb'}) {
// This app serves the Parse API directly.
// It's the equivalent of https://api.parse.com/1 in the hosted Parse API.
var api = express();
//api.use("/apps", express.static(__dirname + "/public"));
// File handling needs to be before default middlewares are applied
api.use('/', middlewares.allowCrossDomain, new FilesRouter().getExpressRouter({
maxUploadSize: maxUploadSize
}));
api.use('/', bodyParser.urlencoded({extended: false}), new PublicAPIRouter().expressApp());
// TODO: separate this from the regular ParseServer object
if (process.env.TESTING == 1) {
api.use('/', require('./testing-routes').router);
}
api.use(bodyParser.json({ 'type': '*/*' , limit: maxUploadSize }));
api.use(middlewares.allowCrossDomain);
api.use(middlewares.allowMethodOverride);
api.use(middlewares.handleParseHeaders);
let routers = [
new ClassesRouter(),
new UsersRouter(),
new SessionsRouter(),
new RolesRouter(),
new AnalyticsRouter(),
new InstallationsRouter(),
new FunctionsRouter(),
new SchemasRouter(),
new PushRouter(),
new LogsRouter(),
new IAPValidationRouter(),
new FeaturesRouter(),
];
if (process.env.PARSE_EXPERIMENTAL_CONFIG_ENABLED || process.env.TESTING) {
routers.push(new GlobalConfigRouter());
}
if (process.env.PARSE_EXPERIMENTAL_HOOKS_ENABLED || process.env.TESTING) {
routers.push(new HooksRouter());
}
let routes = routers.reduce((memo, router) => {
return memo.concat(router.routes);
}, []);
let appRouter = new PromiseRouter(routes);
batch.mountOnto(appRouter);
api.use(appRouter.expressApp());
api.use(middlewares.handleParseErrors);
//This causes tests to spew some useless warnings, so disable in test
if (!process.env.TESTING) {
process.on('uncaughtException', (err) => {
if ( err.code === "EADDRINUSE" ) { // user-friendly message for this common error
console.log(`Unable to listen on port ${err.port}. The port is already in use.`);
process.exit(0);
} else {
throw err;
}
});
}
return api;
}
static ParseServer(options) {
let server = new ParseServer(options);
return server.app;
}
static createLiveQueryServer(httpServer, config) {
return new ParseLiveQueryServer(httpServer, config);
}
}
function addParseCloud() {
@@ -268,13 +286,9 @@ function addParseCloud() {
global.Parse = Parse;
}
ParseServer.createLiveQueryServer = function(httpServer, config) {
return new ParseLiveQueryServer(httpServer, config);
let runServer = function(options) {
return ParseServer.ParseServer(options);
}
module.exports = {
ParseServer: ParseServer,
S3Adapter: S3Adapter,
GCSAdapter: GCSAdapter,
FileSystemAdapter: FileSystemAdapter
};
export { S3Adapter, GCSAdapter, FileSystemAdapter };
export { runServer as ParseServer };