diff --git a/commands/serve.js b/commands/serve.js index e30ed897..0007ae13 100644 --- a/commands/serve.js +++ b/commands/serve.js @@ -6,45 +6,55 @@ var superstatic = require('superstatic').server; var Command = require('../lib/command'); var FirebaseError = require('../lib/error'); +var hostingImplicitInit = require('../lib/hostingImplicitInit'); +var hostingInitMiddleware = require('../lib/hostingInitMiddleware'); var logger = require('../lib/logger'); var utils = require('../lib/utils'); +var requireAccess = require('../lib/requireAccess'); var requireConfig = require('../lib/requireConfig'); var checkDupHostingKeys = require('../lib/checkDupHostingKeys'); +var scopes = require('../lib/scopes'); var MAX_PORT_ATTEMPTS = 10; var _attempts = 0; var startServer = function(options) { var config = options.config ? options.config.get('hosting') : {public: '.'}; - var server = superstatic({ - debug: true, - port: options.port, - host: options.host, - config: config, - stack: 'strict' - }).listen(function() { - if (config.public && config.public !== '.') { - logger.info(chalk.bold('Public Directory:'), config.public); - } - logger.info(); - logger.info('Server listening at: ' + chalk.underline(chalk.bold('http://' + options.host + ':' + options.port))); - }); - server.on('error', function(err) { - if (err.code === 'EADDRINUSE') { - var message = 'Port ' + options.port + ' is not available.'; - if (_attempts < MAX_PORT_ATTEMPTS) { - utils.logWarning(message + ' Trying another port...'); - options.port++; - _attempts++; - startServer(options); - } else { - utils.logWarning(message); - throw new FirebaseError('Could not find an open port for development server.', {exit: 1}); + return hostingImplicitInit(options).then(function(init) { + var server = superstatic({ + debug: true, + port: options.port, + host: options.host, + config: config, + stack: 'strict', + before: { + files: hostingInitMiddleware(init) } - } else { - throw new FirebaseError('An error occurred while starting the development server:\n\n' + err.toString(), {exit: 1}); - } + }).listen(function() { + if (config.public && config.public !== '.') { + logger.info(chalk.bold('Public Directory:'), config.public); + } + logger.info(); + logger.info('Server listening at: ' + chalk.underline(chalk.bold('http://' + options.host + ':' + options.port))); + }); + + server.on('error', function(err) { + if (err.code === 'EADDRINUSE') { + var message = 'Port ' + options.port + ' is not available.'; + if (_attempts < MAX_PORT_ATTEMPTS) { + utils.logWarning(message + ' Trying another port...'); + options.port++; + _attempts++; + startServer(options); + } else { + utils.logWarning(message); + throw new FirebaseError('Could not find an open port for development server.', {exit: 1}); + } + } else { + throw new FirebaseError('An error occurred while starting the development server:\n\n' + err.toString(), {exit: 1}); + } + }); }); }; @@ -53,6 +63,7 @@ module.exports = new Command('serve') .option('-p, --port ', 'the port on which to listen (default: 5000)', 5000) .option('-o, --host ', 'the host on which to listen (default: localhost)', 'localhost') .before(requireConfig) + .before(requireAccess, [scopes.CLOUD_PLATFORM]) .before(checkDupHostingKeys) .action(function(options) { logger.info('Starting Firebase development server...'); @@ -64,12 +75,12 @@ module.exports = new Command('serve') utils.logWarning('No Firebase project directory detected. Serving static content from ' + chalk.bold(options.cwd || process.cwd())); } - startServer(options); - - return new RSVP.Promise(function(resolve) { - process.on('SIGINT', function() { - logger.info('Shutting down...'); - resolve(); + return startServer(options).then(function() { + return new RSVP.Promise(function(resolve) { + process.on('SIGINT', function() { + logger.info('Shutting down...'); + resolve(); + }); }); }); }); diff --git a/lib/hostingImplicitInit.js b/lib/hostingImplicitInit.js new file mode 100644 index 00000000..71656a59 --- /dev/null +++ b/lib/hostingImplicitInit.js @@ -0,0 +1,17 @@ +'use strict'; + +var fs = require('fs'); + +var fetchWebSetup = require('./fetchWebSetup'); + +var INIT_TEMPLATE = fs.readFileSync(__dirname + '/../templates/hosting/init.js', 'utf8'); + +module.exports = function(options) { + return fetchWebSetup(options).then(function(config) { + var configJson = JSON.stringify(config, null, 2); + return { + js: INIT_TEMPLATE.replace('{/*--CONFIG--*/}', configJson), + json: configJson + }; + }); +}; diff --git a/lib/hostingInitMiddleware.js b/lib/hostingInitMiddleware.js new file mode 100644 index 00000000..0687d829 --- /dev/null +++ b/lib/hostingInitMiddleware.js @@ -0,0 +1,28 @@ +'use strict'; + +var request = require('request'); + +var SDK_PATH_REGEXP = /^\/__\/firebase\/([^/]+)\/([^/]+)$/; + +module.exports = function(init) { + return function(req, res, next) { + var match = req.url.match(SDK_PATH_REGEXP); + if (match) { + var url = 'https://www.gstatic.com/firebasejs/' + match[1] + '/' + match[2]; + var preq = request(url).on('response', function(pres) { + if (pres.statusCode === 404) { + return next(); + } + return preq.pipe(res); + }); + } else if (req.url === '/__/firebase/init.js') { + res.setHeader('Content-Type', 'application/javascript'); + res.end(init.js); + } else if (req.url === '/__/firebase/init.json') { + res.setHeader('Content-Type', 'application/json'); + res.end(init.json); + } else { + next(); + } + }; +}; diff --git a/templates/hosting/init.js b/templates/hosting/init.js new file mode 100644 index 00000000..0470d561 --- /dev/null +++ b/templates/hosting/init.js @@ -0,0 +1,2 @@ +if (typeof firebase === 'undefined') throw new Error('hosting/init-error: Firebase SDK not detected. You must include it before /__/firebase/init.js'); +firebase.initializeApp({/*--CONFIG--*/});