diff --git a/bin/parse-server b/bin/parse-server index 66d01041..d3ade1e8 100755 --- a/bin/parse-server +++ b/bin/parse-server @@ -1,47 +1,2 @@ #!/usr/bin/env node -var express = require('express'); -var ParseServer = require("../lib/index").ParseServer; - -var app = express(); - -var options = {}; -if (process.env.PARSE_SERVER_OPTIONS) { - - options = JSON.parse(process.env.PARSE_SERVER_OPTIONS); - -} else { - - options.databaseURI = process.env.PARSE_SERVER_DATABASE_URI; - options.cloud = process.env.PARSE_SERVER_CLOUD_CODE_MAIN; - options.collectionPrefix = process.env.PARSE_SERVER_COLLECTION_PREFIX; - - // Keys and App ID - options.appId = process.env.PARSE_SERVER_APPLICATION_ID; - options.clientKey = process.env.PARSE_SERVER_CLIENT_KEY; - options.restAPIKey = process.env.PARSE_SERVER_REST_API_KEY; - options.dotNetKey = process.env.PARSE_SERVER_DOTNET_KEY; - options.javascriptKey = process.env.PARSE_SERVER_JAVASCRIPT_KEY; - options.masterKey = process.env.PARSE_SERVER_MASTER_KEY; - options.fileKey = process.env.PARSE_SERVER_FILE_KEY; - // Comma separated list of facebook app ids - var facebookAppIds = process.env.PARSE_SERVER_FACEBOOK_APP_IDS; - - if (facebookAppIds) { - facebookAppIds = facebookAppIds.split(","); - options.facebookAppIds = facebookAppIds; - } - - var oauth = process.env.PARSE_SERVER_OAUTH_PROVIDERS; - if (oauth) { - options.oauth = JSON.parse(oauth); - }; -} - -var mountPath = process.env.PARSE_SERVER_MOUNT_PATH || "/"; -var api = new ParseServer(options); -app.use(mountPath, api); - -var port = process.env.PORT || 1337; -app.listen(port, function() { - console.log('parse-server-example running on http://localhost:'+ port + mountPath); -}); +require("../lib/cli/parse-server"); diff --git a/package.json b/package.json index ba604223..fd348a62 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "babel-runtime": "^6.5.0", "bcrypt-nodejs": "0.0.3", "body-parser": "^1.14.2", + "commander": "^2.9.0", "deepcopy": "^0.6.1", "express": "^4.13.4", "mime": "^1.3.4", diff --git a/src/cli/cli-definitions.js b/src/cli/cli-definitions.js new file mode 100644 index 00000000..19bfd5e1 --- /dev/null +++ b/src/cli/cli-definitions.js @@ -0,0 +1,92 @@ +module.exports = { + "appId": { + env: "PARSE_SERVER_APPLICATION_ID", + help: "Your Parse Application ID", + required: true + }, + "masterKey": { + env: "PARSE_SERVER_MASTER_KEY", + help: "Your Parse Master Key", + required: true + }, + "serverURL": { + env: "PARSE_SERVER_URL", + help: "URL to your parse server with http:// or https://" + }, + "databaseURI": { + env: "PARSE_SERVER_DATABASE_URI", + help: "The full URI to your mongodb database" + }, + "clientKey": { + env: "PARSE_SERVER_CLIENT_KEY", + help: "Key for iOS, MacOS, tvOS clients" + }, + "javascriptKey": { + env: "PARSE_SERVER_JAVASCRIPT_KEY", + help: "Key for the Javascript SDK" + }, + "restAPIKey": { + env: "PARSE_SERVER_REST_API_KEY", + help: "Key for REST calls" + }, + "dotNetKey": { + env: "PARSE_SERVER_DOT_NET_KEY", + help: "Key for Unity and .Net SDK" + }, + "cloud": { + env: "PARSE_SERVER_CLOUD_CODE_MAIN", + help: "Full path to your cloud code main.js" + }, + "push": { + env: "PARSE_SERVER_PUSH", + help: "Configuration for push, as stringified JSON. See https://github.com/ParsePlatform/parse-server/wiki/Push", + action: function(opt) { + return JSON.parse(opt) + } + }, + "oauth": { + env: "PARSE_SERVER_OAUTH_PROVIDERS", + help: "Configuration for your oAuth providers, as stringified JSON. See https://github.com/ParsePlatform/parse-server/wiki/Parse-Server-Guide#oauth", + action: function(opt) { + return JSON.parse(opt) + } + }, + "fileKey": { + env: "PARSE_SERVER_FILE_KEY", + help: "Key for your files", + }, + "facebookAppIds": { + env: "PARSE_SERVER_FACEBOOK_APP_IDS", + help: "Comma separated list for your facebook app Ids", + type: "list", + action: function(opt) { + return opt.split(",") + } + }, + "enableAnonymousUsers": { + env: "PARSE_SERVER_ENABLE_ANON_USERS", + help: "Enable (or disable) anon users, enabled by default", + action: function(opt) { + if (opt == "true" || opt == "1") { + return true; + } + return false; + } + }, + "mountPath": { + env: "PARSE_SERVER_MOUNT_PATH", + help: "Mount path for the server, defaults to /" + }, + "databaseAdapter": { + env: "PARSE_SERVER_DATABASE_ADAPTER", + help: "Adapter module for the database sub-system" + }, + "filesAdapter": { + env: "PARSE_SERVER_FILES_ADAPTER", + help: "Adapter module for the files sub-system" + }, + "loggerAdapter": { + env: "PARSE_SERVER_LOGGER_ADAPTER", + help: "Adapter module for the logging sub-system" + } +}; \ No newline at end of file diff --git a/src/cli/parse-server.js b/src/cli/parse-server.js new file mode 100755 index 00000000..75c567ba --- /dev/null +++ b/src/cli/parse-server.js @@ -0,0 +1,70 @@ +var path = require("path"); +var express = require('express'); +var ParseServer = require("../index").ParseServer; +var definitions = require('./cli-definitions'); +var program = require('./utils/commander'); + +program.loadDefinitions(definitions); + +program + .usage('[options] '); + +program.on('--help', function(){ + console.log(' Get Started guide:'); + console.log(''); + console.log(' Please have a look at the get started guide!') + console.log(' https://github.com/ParsePlatform/parse-server/wiki/Parse-Server-Guide'); + console.log(''); + console.log(''); + console.log(' Usage with npm start'); + console.log(''); + console.log(' $ npm start -- path/to/config.json'); + console.log(' $ npm start -- --appId APP_ID --masterKey MASTER_KEY'); + console.log(' $ npm start -- --appId APP_ID --masterKey MASTER_KEY'); + console.log(''); + console.log(''); + console.log(' Usage:'); + console.log(''); + console.log(' $ parse-server path/to/config.json'); + console.log(' $ parse-server -- --appId APP_ID --masterKey MASTER_KEY'); + console.log(' $ parse-server -- --appId APP_ID --masterKey MASTER_KEY'); + console.log(''); +}); + +program.parse(process.argv, process.env); + +var options = {}; + +if (program.args.length > 0 ) { + var jsonPath = program.args[0]; + jsonPath = path.resolve(jsonPath); + options = require(jsonPath); + console.log(`Configuation loaded from ${jsonPath}`) +} + +var options = Object.keys(definitions).reduce(function (options, key) { + if (program[key]) { + options[key] = program[key]; + } + return options; +}, options); + +options.mountPath = options.mountPath || '/'; + +var app = express(); +var api = new ParseServer(options); +app.use(options.mountPath, api); + +var port = process.env.PORT || 1337; +app.listen(port, function() { + + for (let key in options) { + var value = options[key]; + if (key == "masterKey") { + value = "***REDACTED***"; + } + console.log(`${key}: ${value}`); + } + console.log(''); + console.log('parse-server running on http://localhost:'+ port + options.mountPath); +}); diff --git a/src/cli/utils/commander.js b/src/cli/utils/commander.js new file mode 100644 index 00000000..ce074ce8 --- /dev/null +++ b/src/cli/utils/commander.js @@ -0,0 +1,69 @@ +var program = require('commander'); + +var _definitions; +var _reverseDefinitions; + +program.loadDefinitions = function(definitions, prefix = "") { + _definitions = definitions; + Object.keys(definitions).reduce(function(program, opt){ + if (typeof definitions[opt] == "object") { + const additionalOptions = definitions[opt]; + if (additionalOptions.required === true) { + return program.option(`--${opt} <${opt}>`, additionalOptions.help, additionalOptions.action); + } else { + return program.option(`--${opt} [${opt}]`, additionalOptions.help, additionalOptions.action); + } + } + return program.option(`--${opt} [${opt}]`) + }, program); + + _reverseDefinitions = Object.keys(definitions).reduce(function(object, key){ + let value = definitions[key]; + if (typeof value == "object") { + value = value.env; + } + if (value) { + object[value] = key; + } + return object; + }, {}); + + program.on('--help', function(){ + console.log(' Configure From Environment:'); + console.log(''); + Object.keys(_reverseDefinitions).forEach(function(key){ + console.log(` $ ${key}='${_reverseDefinitions[key]}'`); + }); + console.log(''); + }); +} + +var envParser = function(env = {}) { + return Object.keys(_reverseDefinitions).reduce(function(options, key){ + if (env[key]) { + const originalKey = _reverseDefinitions[key]; + let action = function(option) {return option;} + if (typeof _definitions[originalKey] === "object") { + action = _definitions[originalKey].action || action; + } + options[_reverseDefinitions[key]] = action(env[key]); + } + return options; + }, {}); +} + +program._parse = program.parse; + +program.parse = function(args, env) { + program._parse(args); + // Parse the environment first + var envOptions = envParser(env); + // Load the env if not passed from command line + Object.keys(envOptions).forEach(function(key){ + if (!program[key]) { + program[key] = envOptions[key]; + } + }); +} + +module.exports = program;