UNPKG

jive-sdk

Version:

Node.js SDK for Jive Software to assist with the development of add-ons

319 lines (265 loc) 10.7 kB
/* * Copyright 2013 Jive Software * * 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 * * http://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. */ var express = require('express'), favicon = require('serve-favicon'), path = require('path'), errorHandler = require('errorhandler'), logger = require('morgan'), service = require('./service'), jive = require('../api'), consolidate = require('consolidate'), mustache = consolidate.mustache, q = require('q'), extension = require('./extension/extension'), security = require("./security"); var alreadyBootstrapped = false; var adminApp; var primaryApp; /** * @private * @param options */ var validateServiceOptions = function (options) { // options must be present if ( !options ) { throw 'Undefined options'; } var errors = []; if ( !options['clientUrl'] ) { errors.push('Setup parameter clientUrl is required'); } if ( errors.length > 0 ) { throw 'Errors were found in ' + ' in the configuration:\n' + errors; } }; var setupExpressApp = function (app, rootDir, config) { if ( !app ) { return q.fcall(function() { jive.logger.warn("Warning - app not specified."); } ); } primaryApp = app; app.engine('html', mustache); app.set('view engine', 'html'); app.set('views', rootDir + '/public/tiles'); app.use(express.static(path.join(rootDir, 'public'))); // alias /__public__ to the public directory in the service app.use( '/__public__', express.static(path.join(rootDir, 'public')) ); app.use(favicon(process.cwd() + '/public/favicon.ico')); app.set('port', config['port']); app.set('hostname', config['hostname']); jive.logger.debug('Global framework routes:'); app.post('/registration', service.routes.tiles.registration); service.security().lockRoute({ 'verb' : 'post', 'path' : '/registration' }); app.post('/unregister', service.routes.tiles.unregister); service.security().lockRoute({ 'verb' : 'post', 'path' : '/unregister' }); app.post('/jive/oauth/register', service.routes.jive.oauthRegister); app.post('/jive/oauth/unregister', service.routes.jive.oauthUnregister); jive.logger.debug("POST /registration"); jive.logger.debug("POST /unregister"); jive.logger.debug("POST /jive/oauth/register"); if ( service.monitoring().isActive() ) { jive.logger.debug("GET /jive/monitoring"); } // wire in an sdk app with its own views var jiveSdkApp = express(); jiveSdkApp.engine('html js', mustache); jiveSdkApp.engine('js', mustache); jiveSdkApp.set('view engine', 'html js'); jiveSdkApp.set('views', __dirname + '/../views' ); // assume that views will be in the root jive-sdk folder app.use( jiveSdkApp ); // oauth2 endpoints jiveSdkApp.get('/javascripts/oauth2client.js', function(req, res) { res.render('oauth2client.js'); }); jive.logger.debug('Global dev framework routes:'); app.get('/tiles', service.routes.dev.tiles); app.get('/dev/tiles', service.routes.dev.tiles); jive.logger.debug("/dev/tiles"); /*** MOVED THIS FROM SERVICE.JS - NEEDS TO BE LAST!!!!!????? ****/ /*** SEE: http://expressjs.com/en/guide/error-handling.html ***/ app.use(errorHandler()); return q.fcall(function() { jive.logger.debug("setupExpressApp - Complete."); } ); }; var wireAdminEndpoints = function(appToUse, options) { console.log('wireAdminEndpoints'); if ( !appToUse ) { return; } if ( service.monitoring().isActive() ) { // alias for monitoring endpoint appToUse.get('/healthcheck', service.routes.monitoring.healthCheck); appToUse.get('/jive/monitoring', service.routes.monitoring.healthCheckJive); } appToUse.get('/ping', service.routes.monitoring.ping); appToUse.get('/metrics', service.routes.monitoring.metrics); var monitoring = jive.service.monitoring(); var dbMonitor = monitoring.createPersistenceMonitor(); monitoring.addMonitor(dbMonitor); var monitoringInterval = options['monitoringInterval']; var task = new jive.tasks.build(monitoring.runMonitoring, monitoringInterval); jive.tasks.schedule(task, jive.service.scheduler()); monitoring.addMetric( monitoring.createUptimeMetric() ); monitoring.addMetric( monitoring.createCodeVersionMetric() ); jive.logger.info("Service logging endpoints enabled: /healthcheck, /ping, /metrics"); // setup statsd client var statsdClientConfig = options['statsdClientConfig']; if ( statsdClientConfig ) { var host = statsdClientConfig['host'] || 'localhost'; var port = statsdClientConfig['port'] || 8125; var interval = statsdClientConfig['interval'] || 1000; jive.logger.info("Enabling statsd client host:", host, "port:", port, "interval:", interval); var statsdTask = new jive.tasks.build(monitoring.runStatsdClient, interval); jive.tasks.schedule(statsdTask, jive.service.scheduler()); } }; var setupScheduler = function() { var deferred = q.defer(); // add base events jive.events.systemEvents.forEach(function(handlerInfo) { jive.events.registerEventListener(handlerInfo['event'], handlerInfo['handler'], { 'description' : handlerInfo['description'] }); }); service.scheduler().init(jive.events.eventHandlerMap, service.options, jive); deferred.resolve(); return deferred.promise; }; var setupHttp = function(app, rootDir, options) { var deferred = q.defer(); if ( service.role.isHttp() ) { jive.logger.warn('Starting service in HTTP mode'); setupExpressApp(app, rootDir, options).then( function() { jive.logger.info("Http node setup"); deferred.resolve(); }); } else { deferred.resolve(); } return deferred.promise; }; var getSDKVersion = function() { var sdkPackagePath = __dirname + '/../../package.json'; return jive.util.fsexists( sdkPackagePath ).then( function(exists) { if ( exists ) { return jive.util.fsreadJson( sdkPackagePath ).then( function(packageContents) { if ( packageContents ) { return packageContents['version']; } else { return null; } }); } else { return null; } }); }; var setupExtension = function(options, tilesDir, appsDir, cartridgesDir, storagesDir, servicesDir) { if ( options['skipCreateExtension'] ) { return q.resolve(); } return extension.prepare('', tilesDir, appsDir, cartridgesDir, storagesDir, servicesDir, options['packageApps'] === true ); }; var setupMonitoring = function(options) { if ( !options ) { // skip scheduling monitoring if no options return q.resolve(); } var monitoringInterval = options['monitoringInterval']; if ( !monitoringInterval || options['suppressMonitoring']) { // skip monitoring if no monitoring interval return q.resolve(); } var adminPort = options['adminPort']; var deferred = q.defer(); if ( adminPort && adminPort !== primaryApp.get("port") ) { // spawn a new server listening on the admin port adminApp = express(); if ( options && !options['suppressHttpLogging'] ) { adminApp.use(morgan('dev')); } var protocol = require('url') .parse(jive.service.serviceURL()) .protocol .toLowerCase() .replace(':', ''); var protocolLibrary; if ( protocol == 'http' ) { protocolLibrary = require('http'); } if ( protocol == 'https' ) { protocolLibrary = require('https'); } if ( !protocolLibrary ) { return q.resolve(); } var server = protocolLibrary.createServer(adminApp).listen( adminPort, primaryApp.get('hostname') || undefined, function () { jive.logger.info("Express admin endpoint listening on " + server.address().address +':'+server.address().port); wireAdminEndpoints(adminApp, options); deferred.resolve(); }); } else { wireAdminEndpoints(primaryApp, options); deferred.resolve(); } return deferred.promise; }; /** * @private * @param app Required. * @param rootDir Optional; defaults to process.cwd() if not specified */ exports.start = function (app, options, rootDir, tilesDir, appsDir, cartridgesDir, storagesDir, servicesDir) { if ( alreadyBootstrapped ) { return q.fcall( function() { jive.logger.warn('Already bootstrapped, skipping.'); }); } jive.logger.info("Running bootstrap."); // mark this already bootstrapped so we don't do it again alreadyBootstrapped = true; validateServiceOptions(options); return setupScheduler() .then( function() { return setupHttp(app, rootDir, options) }) .then( function() { return setupExtension(options, tilesDir, appsDir, cartridgesDir, storagesDir, servicesDir) }) .then( function() { return setupMonitoring(options) }) .then( function() { return jive.util.fsexists( __dirname + '/../../package.json') }) .then( function() { return getSDKVersion() }) .then( function(sdkVersion) { jive.logger.info("Bootstrap complete."); if ( sdkVersion ) { jive.logger.info( "Jive SDK version " + sdkVersion ); } jive.logger.info("Started service in ", service.options.role || 'self-contained', "mode"); jive.events.emit("serviceBootstrapped"); return q.resolve(); }); }; exports.teardown = function() { jive.logger.info("Running teardown."); return service.persistence().close().then( function() { return service.scheduler().shutdown(); }).then( function( ){ // clear all events jive.events.reset(); alreadyBootstrapped = false; jive.logger.info("Teardown complete."); return q.resolve(); }); };