<commit_before>"use strict";

/**
 * Main server.
 * Handles a very simple kind of dependency injection, to be refactored to some service
 * registry ting.
 *
 */

    var mod_connect         = require('connect')
    , mod_sys               = require('sys')
    , mod_path              = require('path')
    , mod_resourceservice   = null
    , mod_resourcemanager   = null
    , mod_tagmanager        = require('./tagmanager.js')
    , mod_cache             = require('./cache.js')
    , mod_socketio          = require('./socketio.js')
    , mod_modules           = null
    , mod_fs                = require('fs')
    , cache                 = null
    , redisclient           = null
    , logger                = require('./logger.js').getLogger(mod_path.basename(module.filename))

if (process.argv.length < 3) {
    logger.error('usage: server <configfile>');
    process.exit();
}

// [TBD] handle arguments properly
// [TBD] dynamic config service (requires dependency management first)
var config = null;
logger.info('reading config from ' + process.argv[2]);
mod_fs.readFile(process.argv[2], function (err, data) {
    if (err) {
        logger.error('error reading configuration');
        process.exit();
    }
    config = JSON.parse(data);
    logger.info('config loaded');
    mod_cache.configure(config);
    mod_resourcemanager = require('./resourcemanager.js')(config, mod_cache);
    mod_resourceservice = require('./resourceservice.js')(config, mod_resourcemanager, mod_cache);
    mod_tagmanager.setTagList(config.taglib);
    mod_modules = require('./modules.js')(mod_tagmanager, mod_resourcemanager);

    if (config.remotecontrol) {
        logger.info('setting up remote control');
        redisclient = require('./redisclient.js');
        redisclient.init(mod_tagmanager);
    }

    createServer(config);
    logger.info('server started on port ' + config.server.port + ', ' + new Date());
});

function createServer(config) {
    var server = mod_connect.createServer(
        mod_connect.favicon()
        , mod_connect.router(function (app) {
                app.get(/^\/modules\/([^\.]*)\/(.*\.html)$/,                mod_modules.handleViewRequest);
                app.get(/^\/modules\/([^\.]*)\/controller.*\/(.*\.js)$/,    mod_modules.handleControllerRequest);
                app.get(/^\/resources(.*)$/,                                mod_resourceservice.handleRequest);
                //app.get(/instances\/(.*)/,                                  mod_instances.handleInstanceRequest);
            }
        )
        , mod_connect.static(config.server.documentRoot)
        , mod_connect.logger()
    );

    if (config.websockets) {
        logger.info('starting websockets');
        var io = require('socket.io').listen(server);
        mod_socketio.init(io);
    }
    server.listen(config.server.port);
}

// process.on('SIGINT', function () {
//  process.exit();
// });<commit_msg>additional routes for controller request handler<commit_after>"use strict";

/**
 * Main server.
 * Handles a very simple kind of dependency injection, to be refactored to some service
 * registry ting.
 *
 */

    var mod_connect         = require('connect')
    , mod_sys               = require('sys')
    , mod_path              = require('path')
    , mod_resourceservice   = null
    , mod_resourcemanager   = null
    , mod_tagmanager        = require('./tagmanager.js')
    , mod_cache             = require('./cache.js')
    , mod_socketio          = require('./socketio.js')
    , mod_modules           = null
    , mod_fs                = require('fs')
    , cache                 = null
    , redisclient           = null
    , logger                = require('./logger.js').getLogger(mod_path.basename(module.filename))

if (process.argv.length < 3) {
    logger.error('usage: server <configfile>');
    process.exit();
}

// [TBD] handle arguments properly
// [TBD] dynamic config service (requires dependency management first)
var config = null;
logger.info('reading config from ' + process.argv[2]);
mod_fs.readFile(process.argv[2], function (err, data) {
    if (err) {
        logger.error('error reading configuration');
        process.exit();
    }
    config = JSON.parse(data);
    logger.info('config loaded');
    mod_cache.configure(config);
    mod_resourcemanager = require('./resourcemanager.js')(config, mod_cache);
    mod_resourceservice = require('./resourceservice.js')(config, mod_resourcemanager, mod_cache);
    mod_tagmanager.setTagList(config.taglib);
    mod_modules = require('./modules.js')(mod_tagmanager, mod_resourcemanager);

    if (config.remotecontrol) {
        logger.info('setting up remote control');
        redisclient = require('./redisclient.js');
        redisclient.init(mod_tagmanager);
    }

    createServer(config);
    logger.info('server started on port ' + config.server.port + ', ' + new Date());
});

function createServer(config) {
    var server = mod_connect.createServer(
        mod_connect.favicon()
        , mod_connect.bodyParser()
        , mod_connect.router(function (app) {
                app.get(/^\/modules\/([^\.]*)\/(.*\.html)$/,                mod_modules.handleViewRequest);
                app.get(/^\/modules\/([^\.]*)\/controller.*\/(.*\.js)$/,    mod_modules.handleControllerRequest);
                app.put(/^\/modules\/([^\.]*)\/controller.*\/(.*\.js)$/,    mod_modules.handleControllerRequest);
                app.post(/^\/modules\/([^\.]*)\/controller.*\/(.*\.js)$/,   mod_modules.handleControllerRequest);
                app.delete(/^\/modules\/([^\.]*)\/controller.*\/(.*\.js)$/, mod_modules.handleControllerRequest);
                app.get(/^\/resources(.*)$/,                                mod_resourceservice.handleRequest);
                //app.get(/instances\/(.*)/,                                  mod_instances.handleInstanceRequest);
            }
        )
        , mod_connect.static(config.server.documentRoot)
        , mod_connect.logger()
    );

    if (config.websockets) {
        logger.info('starting websockets');
        var io = require('socket.io').listen(server);
        mod_socketio.init(io);
    }
    server.listen(config.server.port);
}

// process.on('SIGINT', function () {
//  process.exit();
// });<|endoftext|>


<commit_before>/**
 * Simple web server.
 *
 * Usage:
 *  let server=require("./server");
 *  server.start() //default config
 *  server.start(configuration) //non default configuration
 *  server.start(configuration).then((s)=>{...}) //once the server has started, execute the callback
 *
 * Application default skeleton:
 * --app [folder] (REST services, custom html, templates, etc)
 * --public[folder] (html,js,css static files)
 * --other stuff (private to the server, but it could be accessed from js files at /app by using require('../'))
 * --main.js (start the web server)
 */

module.exports={
  start:start,
  use:use
}

let http = require("http")
let https = require("https")
let path = require("path")
let url = require("url")
let fs = require("fs")
let router = require("./router")
let plugins = require('./plugins')
let proxy = require('./proxy-external')//reverse proxy
let security=require('./security')
//let proxy=require('./proxy-custom')

let server // the HTTP server
let pathStatic // path to static resources (html,css,js,img,...)
let pathDynamic // path to dynamic resources (server-side templates, REST services,...)

/*
 ██████  ██████  ███    ██ ███████ ██  ██████  ██    ██ ██████   █████  ████████ ██  ██████  ███    ██
██      ██    ██ ████   ██ ██      ██ ██       ██    ██ ██   ██ ██   ██    ██    ██ ██    ██ ████   ██
██      ██    ██ ██ ██  ██ █████   ██ ██   ███ ██    ██ ██████  ███████    ██    ██ ██    ██ ██ ██  ██
██      ██    ██ ██  ██ ██ ██      ██ ██    ██ ██    ██ ██   ██ ██   ██    ██    ██ ██    ██ ██  ██ ██
 ██████  ██████  ██   ████ ██      ██  ██████   ██████  ██   ██ ██   ██    ██    ██  ██████  ██   ████
*/

let configuration={
  ssl:{
    /*key: fs.readFileSync('~/webapp/server.key'),
    cert: fs.readFileSync('~/webapp/server.crt')
    */
  },
  serverName:'',
  welcomePage:'index.html',
  port:'8080',
  staticFolder:'public',
  dynamicFolder:'app',
  rules:{'/':'index.html'}
}

function configure(customConfiguration){
  if(customConfiguration){
    for (let prop of Object.keys(customConfiguration)){
      if(prop!=='rules') configuration[prop]=customConfiguration[prop]
      else{
        let newRules=customConfiguration[prop]
        for(let name of Object.keys(newRules)) configuration[prop][name]=newRules[name]
      }
    }
  }
  pathStatic = path.join(process.cwd(),configuration.staticFolder)
  pathDynamic = path.join(process.cwd(),configuration.dynamicFolder)
  router.load(configuration.rules)
}

/*
███████ ████████  █████  ██████  ████████
██         ██    ██   ██ ██   ██    ██
███████    ██    ███████ ██████     ██
     ██    ██    ██   ██ ██   ██    ██
███████    ██    ██   ██ ██   ██    ██
*/

/**
 * Start the server
 * @param {object} customConfiguration. Override default configuration
 * @return {http.Server} server
 */
async function start(customConfiguration){
  try{
    configure(customConfiguration)
    use(security.protect())
    if (configuration.ssl.key){
      server=https.createServer(configuration.ssl).listen(configuration.port)
    }else{
      server=http.createServer().listen(configuration.port)
    }
    console.log('---------------------------')
    console.log("server at localhost:"+configuration.port)
    console.log('---------------------------')
    server.on('request', function(request, response) {
      request.on('error', (request, response)=>dynamicPage('500',null,request, response))
      dispatch(request,response)
    })
    return server
  }catch(err){
    console.error(err)
    return error
  }
}

function getRoute(request){
  let page=url.parse(request.url).pathname
  page=securityPreventPrivateFiles(page)
  return router.resolve(page)
}

async function executePlugins(route,request,response){
  return plugins.executePlugins(route,request,response)
}

/*
██████  ██ ███████ ██████   █████  ████████  ██████ ██   ██ ███████ ██████
██   ██ ██ ██      ██   ██ ██   ██    ██    ██      ██   ██ ██      ██   ██
██   ██ ██ ███████ ██████  ███████    ██    ██      ███████ █████   ██████
██   ██ ██      ██ ██      ██   ██    ██    ██      ██   ██ ██      ██   ██
██████  ██ ███████ ██      ██   ██    ██     ██████ ██   ██ ███████ ██   ██
*/

async function dispatch(request,response){
  try{
    let route=getRoute(request)
    if(isStaticPage(route.path)){
      await dispatchContent(route,request,response) //if static, no need to execute plugins (fast responses)
    }else{
      await executePlugins(route,request,response)
      await dispatchContent(route,request,response)
    }
  }catch(err){
    if(!response.finished)  await dynamicPage('500',null,request, response)
    console.error(err)
    throw err
  }
}

async function dispatchContent(route,request,response){
  try {
    let realPath=route.path
    if (realPath!=='/' && realPath.endsWith('/')) realPath=realPath.substring(0,realPath.length-1)
    if (isProxyPage(realPath,request)){
      proxyPage(realPath,request, response)
    }else if (isDynamicPage(realPath)){
      if(request.method==='POST'  || request.method==='PUT' || request.method==='DELETE'){
        let body=''
        request.on('data', function(data) {
          body=body+data
          if (body.length>1000000) security.block(request)
        })
        request.on('end', function() {
          this.body=body
          dynamicPage(realPath,route.params,request, response).catch(err=>dynamicPage('500',err,request, response))
        })
      }else{
          dynamicPage(realPath,route.params,request, response).catch(err=>{
            dynamicPage('500',err,request, response)
          })
      }
    }else{
      await staticPage(realPath,request, response)
    }
  } catch (e) {
    console.error(err)
    await dynamicPage('500',request, response)
  }
}

/*
███████ ████████  █████  ████████ ██  ██████     ██████   █████   ██████  ███████
██         ██    ██   ██    ██    ██ ██          ██   ██ ██   ██ ██       ██
███████    ██    ███████    ██    ██ ██          ██████  ███████ ██   ███ █████
     ██    ██    ██   ██    ██    ██ ██          ██      ██   ██ ██    ██ ██
███████    ██    ██   ██    ██    ██  ██████     ██      ██   ██  ██████  ███████
*/

/**
 * Serve static content (html,js,css,img,...)
 */
async function staticPage(page,request, response){
  let fullPath = path.join(process.cwd(),configuration.staticFolder, page)
  fs.exists(fullPath, function(exists) {
    if (!exists) {
      response.writeHead(404, {"Content-Type": "text/plain"});
      response.write('NOT FOUND');
      response.end();
    } else {
      fs.readFile(fullPath, "binary", function(err, file) {
        if (err) {
          response.writeHead(500, {"Content-Type": "text/plain"});
          response.write(err + "\n");
        } else {
          response.writeHead(200);
          response.write(file, "binary");
        }
        response.end();
      });
    }
  });
}

/*
██████  ██    ██ ███    ██  █████  ███    ███ ██  ██████     ██████   █████   ██████  ███████
██   ██  ██  ██  ████   ██ ██   ██ ████  ████ ██ ██          ██   ██ ██   ██ ██       ██
██   ██   ████   ██ ██  ██ ███████ ██ ████ ██ ██ ██          ██████  ███████ ██   ███ █████
██   ██    ██    ██  ██ ██ ██   ██ ██  ██  ██ ██ ██          ██      ██   ██ ██    ██ ██
██████     ██    ██   ████ ██   ██ ██      ██ ██  ██████     ██      ██   ██  ██████  ███████
*/

/**
* Serve dynamic content:
* - server-side templates(by js or by template engines)
* - REST services (/services/resource/param1/param2/...)
*/
async function dynamicPage(page,paramsREST,request,response){
  let resource=page
  let params=paramsREST
  try{
    let fullResourcePath=path.join(process.cwd(),configuration.dynamicFolder, resource+'.js')
    if (fs.existsSync(fullResourcePath)===false){
      return staticPage(page+'.html',request, response) // server/test=server/test.html
    }
    let service=require(fullResourcePath)
    let data=await service[request.method.toLowerCase()](request,response,params)
    if (typeof(data)==='object'){
      let result=JSON.stringify(data)
      response.setHeader('Content-Type','application/json; charset=utf-8')
      response.write(result)
    }else if (isNaN(data)==false){
      response.write(String(data))
    }else {
      response.write(data)
    }
  }catch(err){
    console.error('error is:'+err)
    throw err
  }finally{
    response.end()
  }
}

/*
██████  ██████   ██████  ██   ██ ██    ██     ██████   █████   ██████  ███████
██   ██ ██   ██ ██    ██  ██ ██   ██  ██      ██   ██ ██   ██ ██       ██
██████  ██████  ██    ██   ███     ████       ██████  ███████ ██   ███ █████
██      ██   ██ ██    ██  ██ ██     ██        ██      ██   ██ ██    ██ ██
██      ██   ██  ██████  ██   ██    ██        ██      ██   ██  ██████  ███████
*/

/**
 * Request is actually addressing another server (reverse proxy).
 */
function proxyPage(page,request,response,stop){
  proxy.proxyPage(page,request,response,stop)
}

/*
██    ██ ████████ ██ ██      ███████
██    ██    ██    ██ ██      ██
██    ██    ██    ██ ██      ███████
██    ██    ██    ██ ██           ██
 ██████     ██    ██ ███████ ███████
*/

function hasExtension(page){
  let index=page.lastIndexOf('?')
  if(index>-1) page=page.substring(0,index)
  if (page.indexOf('.')>-1) return true
  else return false
}

/**
 * Prevent unwanted access to non server files (static or dynamic)
 * IMPORTANT: a hole in this function may lead to execute or display any js inside the server,
 * SO BE CAUTIOUS WHEN CHANGING THIS CODE
 * Some tampering examples:
 * - /public/private/pasword.txt/../../private/pasword.txt
 */
function securityPreventPrivateFiles(page){
    if (page==='/'){page=configuration.welcomePage;}
    let fullPath1 = path.join(process.cwd(),configuration.staticFolder, page)
    let fullPath2 = path.join(process.cwd(),configuration.dynamicFolder, page)
  //console.log(page)
    if (fullPath1.indexOf(pathStatic)!==0 && fullPath2.indexOf(pathDynamic)!==0) page= '404.html'
    return page
}

/**
 * Install plugins that are compatible with connect and express
 * Express middleware can also be used as input
 */
function use(func){
  plugins.use(func)
}

/**
 * HML page,js, css,images...etc
 */
function isStaticPage(page){
 return hasExtension(page)
}

/**
 * Private Javascript or template processing
 */
function isDynamicPage(page){
  return !hasExtension(page)
}

/**
 * Calling to aother server http://... instead of the current page
 * A page can be a proxy:
 *  - if current page fulfills an external route
 *  - if referer header fulfills an external route
 */
function isProxyPage(page,request){
  if (page.indexOf('http:')===0 || page.indexOf('https:')===0) {
    return true
  }else{
    if (request && request.headers.referer){
      let route=router.resolve(request.headers.referer)
      let realPath=route.path
      return isProxyPage(realPath)
    }else return false
  }
}
<commit_msg>server: bug on response.end() in finally clause<commit_after>/**
 * Simple web server.
 *
 * Usage:
 *  let server=require("./server");
 *  server.start() //default config
 *  server.start(configuration) //non default configuration
 *  server.start(configuration).then((s)=>{...}) //once the server has started, execute the callback
 *
 * Application default skeleton:
 * --app [folder] (REST services, custom html, templates, etc)
 * --public[folder] (html,js,css static files)
 * --other stuff (private to the server, but it could be accessed from js files at /app by using require('../'))
 * --main.js (start the web server)
 */

module.exports={
  start:start,
  use:use
}

let http = require("http")
let https = require("https")
let path = require("path")
let url = require("url")
let fs = require("fs")
let router = require("./router")
let plugins = require('./plugins')
let proxy = require('./proxy-external')//reverse proxy
let security=require('./security')
//let proxy=require('./proxy-custom')

let server // the HTTP server
let pathStatic // path to static resources (html,css,js,img,...)
let pathDynamic // path to dynamic resources (server-side templates, REST services,...)

/*
 ██████  ██████  ███    ██ ███████ ██  ██████  ██    ██ ██████   █████  ████████ ██  ██████  ███    ██
██      ██    ██ ████   ██ ██      ██ ██       ██    ██ ██   ██ ██   ██    ██    ██ ██    ██ ████   ██
██      ██    ██ ██ ██  ██ █████   ██ ██   ███ ██    ██ ██████  ███████    ██    ██ ██    ██ ██ ██  ██
██      ██    ██ ██  ██ ██ ██      ██ ██    ██ ██    ██ ██   ██ ██   ██    ██    ██ ██    ██ ██  ██ ██
 ██████  ██████  ██   ████ ██      ██  ██████   ██████  ██   ██ ██   ██    ██    ██  ██████  ██   ████
*/

let configuration={
  ssl:{
    /*key: fs.readFileSync('~/webapp/server.key'),
    cert: fs.readFileSync('~/webapp/server.crt')
    */
  },
  serverName:'',
  welcomePage:'index.html',
  port:'8080',
  staticFolder:'public',
  dynamicFolder:'app',
  rules:{'/':'index.html'}
}

function configure(customConfiguration){
  if(customConfiguration){
    for (let prop of Object.keys(customConfiguration)){
      if(prop!=='rules') configuration[prop]=customConfiguration[prop]
      else{
        let newRules=customConfiguration[prop]
        for(let name of Object.keys(newRules)) configuration[prop][name]=newRules[name]
      }
    }
  }
  pathStatic = path.join(process.cwd(),configuration.staticFolder)
  pathDynamic = path.join(process.cwd(),configuration.dynamicFolder)
  router.load(configuration.rules)
}

/*
███████ ████████  █████  ██████  ████████
██         ██    ██   ██ ██   ██    ██
███████    ██    ███████ ██████     ██
     ██    ██    ██   ██ ██   ██    ██
███████    ██    ██   ██ ██   ██    ██
*/

/**
 * Start the server
 * @param {object} customConfiguration. Override default configuration
 * @return {http.Server} server
 */
async function start(customConfiguration){
  try{
    configure(customConfiguration)
    use(security.protect())
    if (configuration.ssl.key){
      server=https.createServer(configuration.ssl).listen(configuration.port)
    }else{
      server=http.createServer().listen(configuration.port)
    }
    console.log('---------------------------')
    console.log("server at localhost:"+configuration.port)
    console.log('---------------------------')
    server.on('request', function(request, response) {
      request.on('error', (request, response)=>dynamicPage('500',null,request, response))
      dispatch(request,response)
    })
    return server
  }catch(err){
    console.error(err)
    return error
  }
}

function getRoute(request){
  let page=url.parse(request.url).pathname
  page=securityPreventPrivateFiles(page)
  return router.resolve(page)
}

async function executePlugins(route,request,response){
  return plugins.executePlugins(route,request,response)
}

/*
██████  ██ ███████ ██████   █████  ████████  ██████ ██   ██ ███████ ██████
██   ██ ██ ██      ██   ██ ██   ██    ██    ██      ██   ██ ██      ██   ██
██   ██ ██ ███████ ██████  ███████    ██    ██      ███████ █████   ██████
██   ██ ██      ██ ██      ██   ██    ██    ██      ██   ██ ██      ██   ██
██████  ██ ███████ ██      ██   ██    ██     ██████ ██   ██ ███████ ██   ██
*/

async function dispatch(request,response){
  try{
    let route=getRoute(request)
    if(isStaticPage(route.path)){
      await dispatchContent(route,request,response) //if static, no need to execute plugins (fast responses)
    }else{
      await executePlugins(route,request,response)
      await dispatchContent(route,request,response)
    }
  }catch(err){
    if(!response.finished)  await dynamicPage('500',null,request, response)
    console.error(err)
    throw err
  }
}

async function dispatchContent(route,request,response){
  try {
    let realPath=route.path
    if (realPath!=='/' && realPath.endsWith('/')) realPath=realPath.substring(0,realPath.length-1)
    if (isProxyPage(realPath,request)){
      proxyPage(realPath,request, response)
    }else if (isDynamicPage(realPath)){
      if(request.method==='POST'  || request.method==='PUT' || request.method==='DELETE'){
        let body=''
        request.on('data', function(data) {
          body=body+data
          if (body.length>1000000) security.block(request)
        })
        request.on('end', function() {
          this.body=body
          dynamicPage(realPath,route.params,request, response).catch(err=>dynamicPage('500',err,request, response))
        })
      }else{
          dynamicPage(realPath,route.params,request, response).catch(err=>{
            dynamicPage('500',err,request, response)
          })
      }
    }else{
      await staticPage(realPath,request, response)
    }
  } catch (e) {
    console.error(err)
    await dynamicPage('500',request, response)
  }
}

/*
███████ ████████  █████  ████████ ██  ██████     ██████   █████   ██████  ███████
██         ██    ██   ██    ██    ██ ██          ██   ██ ██   ██ ██       ██
███████    ██    ███████    ██    ██ ██          ██████  ███████ ██   ███ █████
     ██    ██    ██   ██    ██    ██ ██          ██      ██   ██ ██    ██ ██
███████    ██    ██   ██    ██    ██  ██████     ██      ██   ██  ██████  ███████
*/

/**
 * Serve static content (html,js,css,img,...)
 */
async function staticPage(page,request, response){
  let fullPath = path.join(process.cwd(),configuration.staticFolder, page)
  fs.exists(fullPath, function(exists) {
    if (!exists) {
      response.writeHead(404, {"Content-Type": "text/plain"});
      response.write('NOT FOUND');
      response.end();
    } else {
      fs.readFile(fullPath, "binary", function(err, file) {
        if (err) {
          response.writeHead(500, {"Content-Type": "text/plain"});
          response.write(err + "\n");
        } else {
          response.writeHead(200);
          response.write(file, "binary");
        }
        response.end();
      });
    }
  });
}

/*
██████  ██    ██ ███    ██  █████  ███    ███ ██  ██████     ██████   █████   ██████  ███████
██   ██  ██  ██  ████   ██ ██   ██ ████  ████ ██ ██          ██   ██ ██   ██ ██       ██
██   ██   ████   ██ ██  ██ ███████ ██ ████ ██ ██ ██          ██████  ███████ ██   ███ █████
██   ██    ██    ██  ██ ██ ██   ██ ██  ██  ██ ██ ██          ██      ██   ██ ██    ██ ██
██████     ██    ██   ████ ██   ██ ██      ██ ██  ██████     ██      ██   ██  ██████  ███████
*/

/**
* Serve dynamic content:
* - server-side templates(by js or by template engines)
* - REST services (/services/resource/param1/param2/...)
*/
async function dynamicPage(page,paramsREST,request,response){
  let resource=page
  let params=paramsREST
  try{
    let fullResourcePath=path.join(process.cwd(),configuration.dynamicFolder, resource+'.js')
    if (fs.existsSync(fullResourcePath)===false){
      return staticPage(page+'.html',request, response) // server/test=server/test.html
    }
    let service=require(fullResourcePath)
    let data=await service[request.method.toLowerCase()](request,response,params)
    if (typeof(data)==='object'){
      let result=JSON.stringify(data)
      response.setHeader('Content-Type','application/json; charset=utf-8')
      response.write(result)
    }else if (isNaN(data)==false){
      response.write(String(data))
    }else {
      response.write(data)
    }
    response.end()
  }catch(err){
    console.error('error is:'+err)
    throw err
  }
}

/*
██████  ██████   ██████  ██   ██ ██    ██     ██████   █████   ██████  ███████
██   ██ ██   ██ ██    ██  ██ ██   ██  ██      ██   ██ ██   ██ ██       ██
██████  ██████  ██    ██   ███     ████       ██████  ███████ ██   ███ █████
██      ██   ██ ██    ██  ██ ██     ██        ██      ██   ██ ██    ██ ██
██      ██   ██  ██████  ██   ██    ██        ██      ██   ██  ██████  ███████
*/

/**
 * Request is actually addressing another server (reverse proxy).
 */
function proxyPage(page,request,response,stop){
  proxy.proxyPage(page,request,response,stop)
}

/*
██    ██ ████████ ██ ██      ███████
██    ██    ██    ██ ██      ██
██    ██    ██    ██ ██      ███████
██    ██    ██    ██ ██           ██
 ██████     ██    ██ ███████ ███████
*/

function hasExtension(page){
  let index=page.lastIndexOf('?')
  if(index>-1) page=page.substring(0,index)
  if (page.indexOf('.')>-1) return true
  else return false
}

/**
 * Prevent unwanted access to non server files (static or dynamic)
 * IMPORTANT: a hole in this function may lead to execute or display any js inside the server,
 * SO BE CAUTIOUS WHEN CHANGING THIS CODE
 * Some tampering examples:
 * - /public/private/pasword.txt/../../private/pasword.txt
 */
function securityPreventPrivateFiles(page){
    if (page==='/'){page=configuration.welcomePage;}
    let fullPath1 = path.join(process.cwd(),configuration.staticFolder, page)
    let fullPath2 = path.join(process.cwd(),configuration.dynamicFolder, page)
  //console.log(page)
    if (fullPath1.indexOf(pathStatic)!==0 && fullPath2.indexOf(pathDynamic)!==0) page= '404.html'
    return page
}

/**
 * Install plugins that are compatible with connect and express
 * Express middleware can also be used as input
 */
function use(func){
  plugins.use(func)
}

/**
 * HML page,js, css,images...etc
 */
function isStaticPage(page){
 return hasExtension(page)
}

/**
 * Private Javascript or template processing
 */
function isDynamicPage(page){
  return !hasExtension(page)
}

/**
 * Calling to aother server http://... instead of the current page
 * A page can be a proxy:
 *  - if current page fulfills an external route
 *  - if referer header fulfills an external route
 */
function isProxyPage(page,request){
  if (page.indexOf('http:')===0 || page.indexOf('https:')===0) {
    return true
  }else{
    if (request && request.headers.referer){
      let route=router.resolve(request.headers.referer)
      let realPath=route.path
      return isProxyPage(realPath)
    }else return false
  }
}
<|endoftext|>


<commit_before>var net = require('net'),
    dns = require('dns'),
    util = require('util'),
    inherits = util.inherits,
    EventEmitter = require('events').EventEmitter;

var Parser = require('./server.parser'),
    ipbytes = require('./utils').ipbytes;

var ATYP = require('./constants').ATYP,
    REP = require('./constants').REP;

var BUF_AUTH_NO_ACCEPT = new Buffer([0x05, 0xFF]),
    BUF_REP_INTR_SUCCESS = new Buffer([0x05,
                                       REP.SUCCESS,
                                       0x00,
                                       0x01,
                                       0x00, 0x00, 0x00, 0x00,
                                       0x00, 0x00]),
    BUF_REP_DISALLOW = new Buffer([0x05, REP.DISALLOW]),
    BUF_REP_CMDUNSUPP = new Buffer([0x05, REP.CMDUNSUPP]);

function Server(options, listener) {
  if (!(this instanceof Server))
    return new Server(options, listener);

  var self = this;

  if (typeof options === 'function') {
    self.on('connection', options);
    options = undefined;
  } else if (typeof listener === 'function')
    self.on('connection', listener);

  EventEmitter.call(this);

  this._srv = new net.Server(function(socket) {
    if (self._connections >= self.maxConnections) {
      socket.destroy();
      return;
    }
    ++self._connections;
    socket.once('close', function(had_err) {
      --self._connections;
    });
    self._onConnection(socket);
  }).on('error', function(err) {
    self.emit('error', err);
  }).on('listening', function() {
    self.emit('listening');
  }).on('close', function() {
    self.emit('close');
  });
  this._auths = [];
  if (options && Array.isArray(options.auths)) {
    for (var i = 0, len = options.auths.length; i < len; ++i)
      this.useAuth(options.auths[i]);
  }
  this._debug = (options && typeof options.debug === 'function'
                 ? options.debug
                 : undefined);

  this._connections = 0;
  this.maxConnections = Infinity;
}
inherits(Server, EventEmitter);

Server.prototype._onConnection = function(socket) {
  var self = this,
      parser = new Parser(socket);
  parser.on('error', function(err) {
    if (socket.writable)
      socket.end();
  }).on('methods', function(methods) {
    var auths = self._auths;
    for (var a = 0, alen = auths.length; a < alen; ++a) {
      for (var m = 0, mlen = methods.length; m < mlen; ++m) {
        if (methods[m] === auths[a].METHOD) {
          auths[a].server(socket, function(result) {
            if (result === true) {
              parser.authed = true;
              parser.start();
            } else {
              if (util.isError(result))
                self._debug && self._debug('Error: ' + result.message);
              socket.end();
            }
          });
          socket.write(new Buffer([0x05, auths[a].METHOD]));
          socket.resume();
          return;
        }
      }
    }
    socket.end(BUF_AUTH_NO_ACCEPT);
  }).on('request', function(reqInfo) {
    if (reqInfo.cmd !== 'connect')
      return socket.end(BUF_REP_CMDUNSUPP);

    reqInfo.srcAddr = socket.remoteAddress;
    reqInfo.srcPort = socket.remotePort;

    var handled = false;

    function accept(intercept) {
      if (handled)
        return;
      handled = true;
      if (socket.writable) {
        if (intercept) {
          socket.write(BUF_REP_INTR_SUCCESS);
          socket.removeListener('error', onErrorNoop);
          process.nextTick(function() {
            socket.resume();
          });
          return socket;
        } else
          proxySocket(socket, reqInfo);
      }
    }
    function deny() {
      if (handled)
        return;
      handled = true;
      if (socket.writable)
        socket.end(BUF_REP_DISALLOW);
    }

    if (self._events.connection) {
      self.emit('connection', reqInfo, accept, deny);
      return;
    }

    proxySocket(socket, reqInfo);
  });

  function onClose() {
    if (socket.dstSock && socket.dstSock.writable)
      socket.dstSock.end();
    socket.dstSock = undefined;
  }

  socket.on('error', onErrorNoop)
        .on('end', onClose)
        .on('close', onClose);
};

Server.prototype.useAuth = function(auth) {
  if (typeof auth !== 'object'
      || typeof auth.server !== 'function'
      || auth.server.length !== 2)
    throw new Error('Invalid authentication handler');
  else if (this._auths.length >= 255)
    throw new Error('Too many authentication handlers (limited to 255).');

  this._auths.push(auth);

  return this;
};

Server.prototype.listen = function() {
  this._srv.listen.apply(this._srv, arguments);
  return this;
};

Server.prototype.address = function() {
  return this._srv.address();
};

Server.prototype.getConnections = function(cb) {
  this._srv.getConnections(cb);
};

Server.prototype.close = function(cb) {
  this._srv.close(cb);
  return this;
};

Server.prototype.ref = function() {
  this._srv.ref();
};

Server.prototype.unref = function() {
  this._srv.unref();
};

exports.Server = Server;
exports.createServer = function(opts, listener) {
  return new Server(opts, listener);
};

function onErrorNoop(err) {}

function proxySocket(socket, req) {
  dns.lookup(req.dstAddr, function(err, dstIP) {
    if (err) {
      handleProxyError(socket, err);
      return;
    }

    function onError(err) {
      if (!connected)
        handleProxyError(socket, err);
    }

    var dstSock = new net.Socket(),
        connected = false;

    dstSock.setKeepAlive(false);
    dstSock.on('error', onError)
           .on('connect', function() {
             connected = true;
             if (socket.writable) {
              var localbytes = ipbytes(dstSock.localAddress),
                  len = localbytes.length,
                  bufrep = new Buffer(6 + len),
                  p = 4;
              bufrep[0] = 0x05;
              bufrep[1] = REP.SUCCESS;
              bufrep[2] = 0x00;
              bufrep[3] = (len === 4 ? ATYP.IPv4 : ATYP.IPv6);
              for (var i = 0; i < len; ++i, ++p)
                bufrep[p] = localbytes[i];
              bufrep.writeUInt16BE(dstSock.localPort, p, true);

              socket.write(bufrep);
              socket.pipe(dstSock).pipe(socket);
              socket.resume();
             } else if (dstSock.writable)
              dstSock.end();
           })
           .connect(req.dstPort, dstIP);
    socket.dstSock = dstSock;
  });
}

function handleProxyError(socket, err) {
  if (socket.writable) {
    var errbuf = new Buffer([0x05, REP.GENFAIL]);
    if (err.code) {
      switch (err.code) {
        case 'ENOENT':
        case 'ENOTFOUND':
        case 'ETIMEDOUT':
        case 'EHOSTUNREACH':
          errbuf[1] = REP.HOSTUNREACH;
        break;
        case 'ENETUNREACH':
          errbuf[1] = REP.NETUNREACH;
        break;
        case 'ECONNREFUSED':
          errbuf[1] = REP.CONNREFUSED;
        break;
      }
    }
    socket.end(errbuf);
  }
}<commit_msg>Server: add localAddress fallback for node v0.8<commit_after>var net = require('net'),
    dns = require('dns'),
    util = require('util'),
    inherits = util.inherits,
    EventEmitter = require('events').EventEmitter;

var Parser = require('./server.parser'),
    ipbytes = require('./utils').ipbytes;

var ATYP = require('./constants').ATYP,
    REP = require('./constants').REP;

var BUF_AUTH_NO_ACCEPT = new Buffer([0x05, 0xFF]),
    BUF_REP_INTR_SUCCESS = new Buffer([0x05,
                                       REP.SUCCESS,
                                       0x00,
                                       0x01,
                                       0x00, 0x00, 0x00, 0x00,
                                       0x00, 0x00]),
    BUF_REP_DISALLOW = new Buffer([0x05, REP.DISALLOW]),
    BUF_REP_CMDUNSUPP = new Buffer([0x05, REP.CMDUNSUPP]);

function Server(options, listener) {
  if (!(this instanceof Server))
    return new Server(options, listener);

  var self = this;

  if (typeof options === 'function') {
    self.on('connection', options);
    options = undefined;
  } else if (typeof listener === 'function')
    self.on('connection', listener);

  EventEmitter.call(this);

  this._srv = new net.Server(function(socket) {
    if (self._connections >= self.maxConnections) {
      socket.destroy();
      return;
    }
    ++self._connections;
    socket.once('close', function(had_err) {
      --self._connections;
    });
    self._onConnection(socket);
  }).on('error', function(err) {
    self.emit('error', err);
  }).on('listening', function() {
    self.emit('listening');
  }).on('close', function() {
    self.emit('close');
  });
  this._auths = [];
  if (options && Array.isArray(options.auths)) {
    for (var i = 0, len = options.auths.length; i < len; ++i)
      this.useAuth(options.auths[i]);
  }
  this._debug = (options && typeof options.debug === 'function'
                 ? options.debug
                 : undefined);

  this._connections = 0;
  this.maxConnections = Infinity;
}
inherits(Server, EventEmitter);

Server.prototype._onConnection = function(socket) {
  var self = this,
      parser = new Parser(socket);
  parser.on('error', function(err) {
    if (socket.writable)
      socket.end();
  }).on('methods', function(methods) {
    var auths = self._auths;
    for (var a = 0, alen = auths.length; a < alen; ++a) {
      for (var m = 0, mlen = methods.length; m < mlen; ++m) {
        if (methods[m] === auths[a].METHOD) {
          auths[a].server(socket, function(result) {
            if (result === true) {
              parser.authed = true;
              parser.start();
            } else {
              if (util.isError(result))
                self._debug && self._debug('Error: ' + result.message);
              socket.end();
            }
          });
          socket.write(new Buffer([0x05, auths[a].METHOD]));
          socket.resume();
          return;
        }
      }
    }
    socket.end(BUF_AUTH_NO_ACCEPT);
  }).on('request', function(reqInfo) {
    if (reqInfo.cmd !== 'connect')
      return socket.end(BUF_REP_CMDUNSUPP);

    reqInfo.srcAddr = socket.remoteAddress;
    reqInfo.srcPort = socket.remotePort;

    var handled = false;

    function accept(intercept) {
      if (handled)
        return;
      handled = true;
      if (socket.writable) {
        if (intercept) {
          socket.write(BUF_REP_INTR_SUCCESS);
          socket.removeListener('error', onErrorNoop);
          process.nextTick(function() {
            socket.resume();
          });
          return socket;
        } else
          proxySocket(socket, reqInfo);
      }
    }
    function deny() {
      if (handled)
        return;
      handled = true;
      if (socket.writable)
        socket.end(BUF_REP_DISALLOW);
    }

    if (self._events.connection) {
      self.emit('connection', reqInfo, accept, deny);
      return;
    }

    proxySocket(socket, reqInfo);
  });

  function onClose() {
    if (socket.dstSock && socket.dstSock.writable)
      socket.dstSock.end();
    socket.dstSock = undefined;
  }

  socket.on('error', onErrorNoop)
        .on('end', onClose)
        .on('close', onClose);
};

Server.prototype.useAuth = function(auth) {
  if (typeof auth !== 'object'
      || typeof auth.server !== 'function'
      || auth.server.length !== 2)
    throw new Error('Invalid authentication handler');
  else if (this._auths.length >= 255)
    throw new Error('Too many authentication handlers (limited to 255).');

  this._auths.push(auth);

  return this;
};

Server.prototype.listen = function() {
  this._srv.listen.apply(this._srv, arguments);
  return this;
};

Server.prototype.address = function() {
  return this._srv.address();
};

Server.prototype.getConnections = function(cb) {
  this._srv.getConnections(cb);
};

Server.prototype.close = function(cb) {
  this._srv.close(cb);
  return this;
};

Server.prototype.ref = function() {
  this._srv.ref();
};

Server.prototype.unref = function() {
  this._srv.unref();
};

exports.Server = Server;
exports.createServer = function(opts, listener) {
  return new Server(opts, listener);
};

function onErrorNoop(err) {}

function proxySocket(socket, req) {
  dns.lookup(req.dstAddr, function(err, dstIP) {
    if (err) {
      handleProxyError(socket, err);
      return;
    }

    function onError(err) {
      if (!connected)
        handleProxyError(socket, err);
    }

    var dstSock = new net.Socket(),
        connected = false;

    dstSock.setKeepAlive(false);
    dstSock.on('error', onError)
           .on('connect', function() {
             connected = true;
             if (socket.writable) {
              var localbytes = ipbytes(dstSock.localAddress || '127.0.0.1'),
                  len = localbytes.length,
                  bufrep = new Buffer(6 + len),
                  p = 4;
              bufrep[0] = 0x05;
              bufrep[1] = REP.SUCCESS;
              bufrep[2] = 0x00;
              bufrep[3] = (len === 4 ? ATYP.IPv4 : ATYP.IPv6);
              for (var i = 0; i < len; ++i, ++p)
                bufrep[p] = localbytes[i];
              bufrep.writeUInt16BE(dstSock.localPort, p, true);

              socket.write(bufrep);
              socket.pipe(dstSock).pipe(socket);
              socket.resume();
             } else if (dstSock.writable)
              dstSock.end();
           })
           .connect(req.dstPort, dstIP);
    socket.dstSock = dstSock;
  });
}

function handleProxyError(socket, err) {
  if (socket.writable) {
    var errbuf = new Buffer([0x05, REP.GENFAIL]);
    if (err.code) {
      switch (err.code) {
        case 'ENOENT':
        case 'ENOTFOUND':
        case 'ETIMEDOUT':
        case 'EHOSTUNREACH':
          errbuf[1] = REP.HOSTUNREACH;
        break;
        case 'ENETUNREACH':
          errbuf[1] = REP.NETUNREACH;
        break;
        case 'ECONNREFUSED':
          errbuf[1] = REP.CONNREFUSED;
        break;
      }
    }
    socket.end(errbuf);
  }
}<|endoftext|>


<commit_before>'use strict'

const SocketIO = require('socket.io')
const di = require('di')
const util = require('util')
const spawn = require('child_process').spawn
const tmp = require('tmp')
const fs = require('fs')
const path = require('path')

const NetUtils = require('./utils/net-utils')
const root = global || window || this

const cfg = require('./config')
const logger = require('./logger')
const constant = require('./constants')
const watcher = require('./watcher')
const plugin = require('./plugin')

const createServeFile = require('./web-server').createServeFile
const createServeStaticFile = require('./web-server').createServeStaticFile
const createFilesPromise = require('./web-server').createFilesPromise
const createWebServer = require('./web-server').createWebServer
const preprocessor = require('./preprocessor')
const Launcher = require('./launcher').Launcher
const FileList = require('./file-list')
const reporter = require('./reporter')
const helper = require('./helper')
const events = require('./events')
const KarmaEventEmitter = events.EventEmitter
const EventEmitter = require('events').EventEmitter
const Executor = require('./executor')
const Browser = require('./browser')
const BrowserCollection = require('./browser_collection')
const EmitterWrapper = require('./emitter_wrapper')
const processWrapper = new EmitterWrapper(process)

function createSocketIoServer (webServer, executor, config) {
  const server = new SocketIO.Server(webServer, {
    // avoid destroying http upgrades from socket.io to get proxied websockets working
    destroyUpgrade: false,
    path: config.urlRoot + 'socket.io/',
    transports: config.transports,
    forceJSONP: config.forceJSONP,
    // Default is 5000 in socket.io v2.x and v3.x.
    pingTimeout: config.pingTimeout || 5000
  })

  // hack to overcome circular dependency
  executor.socketIoSockets = server.sockets

  return server
}

class Server extends KarmaEventEmitter {
  constructor (cliOptions, done) {
    super()
    logger.setupFromConfig(cliOptions)

    this.log = logger.create('karma-server')

    this.loadErrors = []

    const config = cfg.parseConfig(cliOptions.configFile, cliOptions)

    this.log.debug('Final config', util.inspect(config, false, /** depth **/ null))

    let modules = [{
      helper: ['value', helper],
      logger: ['value', logger],
      done: ['value', done || process.exit],
      emitter: ['value', this],
      server: ['value', this],
      watcher: ['value', watcher],
      launcher: ['factory', Launcher.factory],
      config: ['value', config],
      preprocess: ['factory', preprocessor.createPriorityPreprocessor],
      fileList: ['factory', FileList.factory],
      webServer: ['factory', createWebServer],
      serveFile: ['factory', createServeFile],
      serveStaticFile: ['factory', createServeStaticFile],
      filesPromise: ['factory', createFilesPromise],
      socketServer: ['factory', createSocketIoServer],
      executor: ['factory', Executor.factory],
      // TODO: Deprecated. Remove in the next major
      customFileHandlers: ['value', []],
      reporter: ['factory', reporter.createReporters],
      capturedBrowsers: ['factory', BrowserCollection.factory],
      args: ['value', {}],
      timer: ['value', {
        setTimeout () {
          return setTimeout.apply(root, arguments)
        },
        clearTimeout
      }]
    }]

    this.on('load_error', (type, name) => {
      this.log.debug(`Registered a load error of type ${type} with name ${name}`)
      this.loadErrors.push([type, name])
    })

    modules = modules.concat(plugin.resolve(config.plugins, this))
    this._injector = new di.Injector(modules)
  }

  async start () {
    const config = this.get('config')
    try {
      this._boundServer = await NetUtils.bindAvailablePort(config.port, config.listenAddress)
      this._boundServer.on('connection', (socket) => {
        // Attach an error handler to avoid UncaughtException errors.
        socket.on('error', (err) => {
          // Errors on this socket are retried, ignore them
          this.log.debug('Ignoring error on webserver connection: ' + err)
        })
      })
      config.port = this._boundServer.address().port
      await this._injector.invoke(this._start, this)
    } catch (err) {
      this.log.error(`Server start failed on port ${config.port}: ${err}`)
      this._close(1)
    }
  }

  get (token) {
    return this._injector.get(token)
  }

  refreshFiles () {
    return this._fileList ? this._fileList.refresh() : Promise.resolve()
  }

  refreshFile (path) {
    return this._fileList ? this._fileList.changeFile(path) : Promise.resolve()
  }

  emitExitAsync (code) {
    const name = 'exit'
    let pending = this.listeners(name).length
    const deferred = helper.defer()

    function resolve () {
      deferred.resolve(code)
    }

    try {
      this.emit(name, (newCode) => {
        if (newCode && typeof newCode === 'number') {
          // Only update code if it is given and not zero
          code = newCode
        }
        if (!--pending) {
          resolve()
        }
      })

      if (!pending) {
        resolve()
      }
    } catch (err) {
      deferred.reject(err)
    }
    return deferred.promise
  }

  async _start (config, launcher, preprocess, fileList, capturedBrowsers, executor, done) {
    if (config.detached) {
      this._detach(config, done)
      return
    }

    this._fileList = fileList

    await Promise.all(
      config.frameworks.map((framework) => this._injector.get('framework:' + framework))
    )

    const webServer = this._injector.get('webServer')
    const socketServer = this._injector.get('socketServer')

    const singleRunDoneBrowsers = Object.create(null)
    const singleRunBrowsers = new BrowserCollection(new EventEmitter())
    let singleRunBrowserNotCaptured = false

    webServer.on('error', (err) => {
      this.log.error(`Webserver fail ${err}`)
      this._close(1)
    })

    const afterPreprocess = () => {
      if (config.autoWatch) {
        const watcher = this.get('watcher')
        this._injector.invoke(watcher)
      }

      webServer.listen(this._boundServer, () => {
        this.log.info(`Karma v${constant.VERSION} server started at ${config.protocol}//${config.hostname}:${config.port}${config.urlRoot}`)

        this.emit('listening', config.port)
        if (config.browsers && config.browsers.length) {
          this._injector.invoke(launcher.launch, launcher).forEach((browserLauncher) => {
            singleRunDoneBrowsers[browserLauncher.id] = false
          })
        }
        if (this.loadErrors.length > 0) {
          this.log.error(new Error(`Found ${this.loadErrors.length} load error${this.loadErrors.length === 1 ? '' : 's'}`))
          this._close(1)
        }
      })
    }

    fileList.refresh().then(afterPreprocess, (err) => {
      this.log.error('Error during file loading or preprocessing\n' + err.stack || err)
      afterPreprocess()
    })

    this.on('browsers_change', () => socketServer.sockets.emit('info', capturedBrowsers.serialize()))

    this.on('browser_register', (browser) => {
      launcher.markCaptured(browser.id)

      if (launcher.areAllCaptured()) {
        this.emit('browsers_ready')

        if (config.autoWatch) {
          executor.schedule()
        }
      }
    })

    if (config.browserConsoleLogOptions && config.browserConsoleLogOptions.path) {
      const configLevel = config.browserConsoleLogOptions.level || 'debug'
      const configFormat = config.browserConsoleLogOptions.format || '%b %T: %m'
      const configPath = config.browserConsoleLogOptions.path
      this.log.info(`Writing browser console to file: ${configPath}`)
      const browserLogFile = fs.openSync(configPath, 'w+')
      const levels = ['log', 'error', 'warn', 'info', 'debug']
      this.on('browser_log', function (browser, message, level) {
        if (levels.indexOf(level.toLowerCase()) > levels.indexOf(configLevel)) {
          return
        }
        if (!helper.isString(message)) {
          message = util.inspect(message, { showHidden: false, colors: false })
        }
        const logMap = { '%m': message, '%t': level.toLowerCase(), '%T': level.toUpperCase(), '%b': browser }
        const logString = configFormat.replace(/%[mtTb]/g, (m) => logMap[m])
        this.log.debug(`Writing browser console line: ${logString}`)
        fs.writeSync(browserLogFile, logString + '\n')
      })
    }

    socketServer.sockets.on('connection', (socket) => {
      this.log.debug(`A browser has connected on socket ${socket.id}`)

      const replySocketEvents = events.bufferEvents(socket, ['start', 'info', 'karma_error', 'result', 'complete'])

      socket.on('error', (err) => {
        this.log.debug('karma server socket error: ' + err)
      })

      socket.on('register', (info) => {
        const knownBrowser = info.id ? (capturedBrowsers.getById(info.id) || singleRunBrowsers.getById(info.id)) : null

        if (knownBrowser) {
          knownBrowser.reconnect(socket, info.isSocketReconnect)
        } else {
          const newBrowser = this._injector.createChild([{
            id: ['value', info.id || null],
            fullName: ['value', (helper.isDefined(info.displayName) ? info.displayName : info.name)],
            socket: ['value', socket]
          }]).invoke(Browser.factory)

          newBrowser.init()

          if (config.singleRun) {
            newBrowser.execute()
            singleRunBrowsers.add(newBrowser)
          }
        }

        replySocketEvents()
      })
    })

    const emitRunCompleteIfAllBrowsersDone = () => {
      if (Object.keys(singleRunDoneBrowsers).every((key) => singleRunDoneBrowsers[key])) {
        this.emit('run_complete', singleRunBrowsers, singleRunBrowsers.getResults(singleRunBrowserNotCaptured, config))
      }
    }

    this.on('browser_complete', (completedBrowser) => {
      if (completedBrowser.lastResult.disconnected && completedBrowser.disconnectsCount <= config.browserDisconnectTolerance) {
        this.log.info(`Restarting ${completedBrowser.name} (${completedBrowser.disconnectsCount} of ${config.browserDisconnectTolerance} attempts)`)

        if (!launcher.restart(completedBrowser.id)) {
          this.emit('browser_restart_failure', completedBrowser)
        }
      } else {
        this.emit('browser_complete_with_no_more_retries', completedBrowser)
      }
    })

    this.on('stop', (done) => {
      this.log.debug('Received stop event, exiting.')
      this._close()
      done()
    })

    if (config.singleRun) {
      this.on('browser_restart_failure', (completedBrowser) => {
        singleRunDoneBrowsers[completedBrowser.id] = true
        emitRunCompleteIfAllBrowsersDone()
      })

      // This is the normal exit trigger.
      this.on('browser_complete_with_no_more_retries', function (completedBrowser) {
        singleRunDoneBrowsers[completedBrowser.id] = true

        if (launcher.kill(completedBrowser.id)) {
          completedBrowser.remove()
        }

        emitRunCompleteIfAllBrowsersDone()
      })

      this.on('browser_process_failure', (browserLauncher) => {
        singleRunDoneBrowsers[browserLauncher.id] = true
        singleRunBrowserNotCaptured = true

        emitRunCompleteIfAllBrowsersDone()
      })

      this.on('run_complete', (browsers, results) => {
        this.log.debug('Run complete, exiting.')
        this._close(results.exitCode)
      })

      this.emit('run_start', singleRunBrowsers)
    }

    if (config.autoWatch) {
      this.on('file_list_modified', () => {
        this.log.debug('List of files has changed, trying to execute')
        if (config.restartOnFileChange) {
          socketServer.sockets.emit('stop')
        }
        executor.schedule()
      })
    }

    processWrapper.on('SIGINT', () => this._close())
    processWrapper.on('SIGTERM', () => this._close())

    const reportError = (error) => {
      this.log.error(error)
      process.emit('infrastructure_error', error)
      this._close(1)
    }

    processWrapper.on('unhandledRejection', (error) => {
      this.log.error(`UnhandledRejection: ${error.stack || error.message || String(error)}`)
      reportError(error)
    })

    processWrapper.on('uncaughtException', (error) => {
      this.log.error(`UncaughtException: ${error.stack || error.message || String(error)}`)
      reportError(error)
    })
  }

  _detach (config, done) {
    const tmpFile = tmp.fileSync({ keep: true })
    this.log.info('Starting karma detached')
    this.log.info('Run "karma stop" to stop the server.')
    this.log.debug(`Writing config to tmp-file ${tmpFile.name}`)
    config.detached = false
    try {
      fs.writeFileSync(tmpFile.name, JSON.stringify(config), 'utf8')
    } catch (e) {
      this.log.error("Couldn't write temporary configuration file")
      done(1)
      return
    }
    const child = spawn(process.argv[0], [path.resolve(__dirname, '../lib/detached.js'), tmpFile.name], {
      detached: true,
      stdio: 'ignore'
    })
    child.unref()
  }

  /**
   * Cleanup all resources allocated by Karma and call the `done` callback
   * with the result of the tests execution.
   *
   * @param [exitCode] - Optional exit code. If omitted will be computed by
   * 'exit' event listeners.
   */
  _close (exitCode) {
    const webServer = this._injector.get('webServer')
    const socketServer = this._injector.get('socketServer')
    const done = this._injector.get('done')

    const webServerCloseTimeout = 3000
    const sockets = socketServer.sockets.sockets

    Object.keys(sockets).forEach((id) => {
      const socket = sockets[id]
      socket.removeAllListeners('disconnect')
      if (!socket.disconnected) {
        process.nextTick(socket.disconnect.bind(socket))
      }
    })

    this.emitExitAsync(exitCode).catch((err) => {
      this.log.error('Error while calling exit event listeners\n' + err.stack || err)
      return 1
    }).then((code) => {
      socketServer.sockets.removeAllListeners()
      socketServer.close()

      let removeAllListenersDone = false
      const removeAllListeners = () => {
        if (removeAllListenersDone) {
          return
        }
        removeAllListenersDone = true
        webServer.removeAllListeners()
        processWrapper.removeAllListeners()
        done(code || 0)
      }

      const closeTimeout = setTimeout(removeAllListeners, webServerCloseTimeout)

      webServer.close(() => {
        clearTimeout(closeTimeout)
        removeAllListeners()
      })
    })
  }

  stop () {
    return this.emitAsync('stop')
  }
}

Server.prototype._start.$inject = ['config', 'launcher', 'preprocess', 'fileList', 'capturedBrowsers', 'executor', 'done']

module.exports = Server
<commit_msg>fix(server): set maxHttpBufferSize to the socket.io v2 default (#3626)<commit_after>'use strict'

const SocketIO = require('socket.io')
const di = require('di')
const util = require('util')
const spawn = require('child_process').spawn
const tmp = require('tmp')
const fs = require('fs')
const path = require('path')

const NetUtils = require('./utils/net-utils')
const root = global || window || this

const cfg = require('./config')
const logger = require('./logger')
const constant = require('./constants')
const watcher = require('./watcher')
const plugin = require('./plugin')

const createServeFile = require('./web-server').createServeFile
const createServeStaticFile = require('./web-server').createServeStaticFile
const createFilesPromise = require('./web-server').createFilesPromise
const createWebServer = require('./web-server').createWebServer
const preprocessor = require('./preprocessor')
const Launcher = require('./launcher').Launcher
const FileList = require('./file-list')
const reporter = require('./reporter')
const helper = require('./helper')
const events = require('./events')
const KarmaEventEmitter = events.EventEmitter
const EventEmitter = require('events').EventEmitter
const Executor = require('./executor')
const Browser = require('./browser')
const BrowserCollection = require('./browser_collection')
const EmitterWrapper = require('./emitter_wrapper')
const processWrapper = new EmitterWrapper(process)

function createSocketIoServer (webServer, executor, config) {
  const server = new SocketIO.Server(webServer, {
    // avoid destroying http upgrades from socket.io to get proxied websockets working
    destroyUpgrade: false,
    path: config.urlRoot + 'socket.io/',
    transports: config.transports,
    forceJSONP: config.forceJSONP,
    // Default is 5000 in socket.io v2.x and v3.x.
    pingTimeout: config.pingTimeout || 5000,
    // Default in v2 is 1e8 and coverage results can fail at 1e6
    maxHttpBufferSize: 1e8
  })

  // hack to overcome circular dependency
  executor.socketIoSockets = server.sockets

  return server
}

class Server extends KarmaEventEmitter {
  constructor (cliOptions, done) {
    super()
    logger.setupFromConfig(cliOptions)

    this.log = logger.create('karma-server')

    this.loadErrors = []

    const config = cfg.parseConfig(cliOptions.configFile, cliOptions)

    this.log.debug('Final config', util.inspect(config, false, /** depth **/ null))

    let modules = [{
      helper: ['value', helper],
      logger: ['value', logger],
      done: ['value', done || process.exit],
      emitter: ['value', this],
      server: ['value', this],
      watcher: ['value', watcher],
      launcher: ['factory', Launcher.factory],
      config: ['value', config],
      preprocess: ['factory', preprocessor.createPriorityPreprocessor],
      fileList: ['factory', FileList.factory],
      webServer: ['factory', createWebServer],
      serveFile: ['factory', createServeFile],
      serveStaticFile: ['factory', createServeStaticFile],
      filesPromise: ['factory', createFilesPromise],
      socketServer: ['factory', createSocketIoServer],
      executor: ['factory', Executor.factory],
      // TODO: Deprecated. Remove in the next major
      customFileHandlers: ['value', []],
      reporter: ['factory', reporter.createReporters],
      capturedBrowsers: ['factory', BrowserCollection.factory],
      args: ['value', {}],
      timer: ['value', {
        setTimeout () {
          return setTimeout.apply(root, arguments)
        },
        clearTimeout
      }]
    }]

    this.on('load_error', (type, name) => {
      this.log.debug(`Registered a load error of type ${type} with name ${name}`)
      this.loadErrors.push([type, name])
    })

    modules = modules.concat(plugin.resolve(config.plugins, this))
    this._injector = new di.Injector(modules)
  }

  async start () {
    const config = this.get('config')
    try {
      this._boundServer = await NetUtils.bindAvailablePort(config.port, config.listenAddress)
      this._boundServer.on('connection', (socket) => {
        // Attach an error handler to avoid UncaughtException errors.
        socket.on('error', (err) => {
          // Errors on this socket are retried, ignore them
          this.log.debug('Ignoring error on webserver connection: ' + err)
        })
      })
      config.port = this._boundServer.address().port
      await this._injector.invoke(this._start, this)
    } catch (err) {
      this.log.error(`Server start failed on port ${config.port}: ${err}`)
      this._close(1)
    }
  }

  get (token) {
    return this._injector.get(token)
  }

  refreshFiles () {
    return this._fileList ? this._fileList.refresh() : Promise.resolve()
  }

  refreshFile (path) {
    return this._fileList ? this._fileList.changeFile(path) : Promise.resolve()
  }

  emitExitAsync (code) {
    const name = 'exit'
    let pending = this.listeners(name).length
    const deferred = helper.defer()

    function resolve () {
      deferred.resolve(code)
    }

    try {
      this.emit(name, (newCode) => {
        if (newCode && typeof newCode === 'number') {
          // Only update code if it is given and not zero
          code = newCode
        }
        if (!--pending) {
          resolve()
        }
      })

      if (!pending) {
        resolve()
      }
    } catch (err) {
      deferred.reject(err)
    }
    return deferred.promise
  }

  async _start (config, launcher, preprocess, fileList, capturedBrowsers, executor, done) {
    if (config.detached) {
      this._detach(config, done)
      return
    }

    this._fileList = fileList

    await Promise.all(
      config.frameworks.map((framework) => this._injector.get('framework:' + framework))
    )

    const webServer = this._injector.get('webServer')
    const socketServer = this._injector.get('socketServer')

    const singleRunDoneBrowsers = Object.create(null)
    const singleRunBrowsers = new BrowserCollection(new EventEmitter())
    let singleRunBrowserNotCaptured = false

    webServer.on('error', (err) => {
      this.log.error(`Webserver fail ${err}`)
      this._close(1)
    })

    const afterPreprocess = () => {
      if (config.autoWatch) {
        const watcher = this.get('watcher')
        this._injector.invoke(watcher)
      }

      webServer.listen(this._boundServer, () => {
        this.log.info(`Karma v${constant.VERSION} server started at ${config.protocol}//${config.hostname}:${config.port}${config.urlRoot}`)

        this.emit('listening', config.port)
        if (config.browsers && config.browsers.length) {
          this._injector.invoke(launcher.launch, launcher).forEach((browserLauncher) => {
            singleRunDoneBrowsers[browserLauncher.id] = false
          })
        }
        if (this.loadErrors.length > 0) {
          this.log.error(new Error(`Found ${this.loadErrors.length} load error${this.loadErrors.length === 1 ? '' : 's'}`))
          this._close(1)
        }
      })
    }

    fileList.refresh().then(afterPreprocess, (err) => {
      this.log.error('Error during file loading or preprocessing\n' + err.stack || err)
      afterPreprocess()
    })

    this.on('browsers_change', () => socketServer.sockets.emit('info', capturedBrowsers.serialize()))

    this.on('browser_register', (browser) => {
      launcher.markCaptured(browser.id)

      if (launcher.areAllCaptured()) {
        this.emit('browsers_ready')

        if (config.autoWatch) {
          executor.schedule()
        }
      }
    })

    if (config.browserConsoleLogOptions && config.browserConsoleLogOptions.path) {
      const configLevel = config.browserConsoleLogOptions.level || 'debug'
      const configFormat = config.browserConsoleLogOptions.format || '%b %T: %m'
      const configPath = config.browserConsoleLogOptions.path
      this.log.info(`Writing browser console to file: ${configPath}`)
      const browserLogFile = fs.openSync(configPath, 'w+')
      const levels = ['log', 'error', 'warn', 'info', 'debug']
      this.on('browser_log', function (browser, message, level) {
        if (levels.indexOf(level.toLowerCase()) > levels.indexOf(configLevel)) {
          return
        }
        if (!helper.isString(message)) {
          message = util.inspect(message, { showHidden: false, colors: false })
        }
        const logMap = { '%m': message, '%t': level.toLowerCase(), '%T': level.toUpperCase(), '%b': browser }
        const logString = configFormat.replace(/%[mtTb]/g, (m) => logMap[m])
        this.log.debug(`Writing browser console line: ${logString}`)
        fs.writeSync(browserLogFile, logString + '\n')
      })
    }

    socketServer.sockets.on('connection', (socket) => {
      this.log.debug(`A browser has connected on socket ${socket.id}`)

      const replySocketEvents = events.bufferEvents(socket, ['start', 'info', 'karma_error', 'result', 'complete'])

      socket.on('error', (err) => {
        this.log.debug('karma server socket error: ' + err)
      })

      socket.on('register', (info) => {
        const knownBrowser = info.id ? (capturedBrowsers.getById(info.id) || singleRunBrowsers.getById(info.id)) : null

        if (knownBrowser) {
          knownBrowser.reconnect(socket, info.isSocketReconnect)
        } else {
          const newBrowser = this._injector.createChild([{
            id: ['value', info.id || null],
            fullName: ['value', (helper.isDefined(info.displayName) ? info.displayName : info.name)],
            socket: ['value', socket]
          }]).invoke(Browser.factory)

          newBrowser.init()

          if (config.singleRun) {
            newBrowser.execute()
            singleRunBrowsers.add(newBrowser)
          }
        }

        replySocketEvents()
      })
    })

    const emitRunCompleteIfAllBrowsersDone = () => {
      if (Object.keys(singleRunDoneBrowsers).every((key) => singleRunDoneBrowsers[key])) {
        this.emit('run_complete', singleRunBrowsers, singleRunBrowsers.getResults(singleRunBrowserNotCaptured, config))
      }
    }

    this.on('browser_complete', (completedBrowser) => {
      if (completedBrowser.lastResult.disconnected && completedBrowser.disconnectsCount <= config.browserDisconnectTolerance) {
        this.log.info(`Restarting ${completedBrowser.name} (${completedBrowser.disconnectsCount} of ${config.browserDisconnectTolerance} attempts)`)

        if (!launcher.restart(completedBrowser.id)) {
          this.emit('browser_restart_failure', completedBrowser)
        }
      } else {
        this.emit('browser_complete_with_no_more_retries', completedBrowser)
      }
    })

    this.on('stop', (done) => {
      this.log.debug('Received stop event, exiting.')
      this._close()
      done()
    })

    if (config.singleRun) {
      this.on('browser_restart_failure', (completedBrowser) => {
        singleRunDoneBrowsers[completedBrowser.id] = true
        emitRunCompleteIfAllBrowsersDone()
      })

      // This is the normal exit trigger.
      this.on('browser_complete_with_no_more_retries', function (completedBrowser) {
        singleRunDoneBrowsers[completedBrowser.id] = true

        if (launcher.kill(completedBrowser.id)) {
          completedBrowser.remove()
        }

        emitRunCompleteIfAllBrowsersDone()
      })

      this.on('browser_process_failure', (browserLauncher) => {
        singleRunDoneBrowsers[browserLauncher.id] = true
        singleRunBrowserNotCaptured = true

        emitRunCompleteIfAllBrowsersDone()
      })

      this.on('run_complete', (browsers, results) => {
        this.log.debug('Run complete, exiting.')
        this._close(results.exitCode)
      })

      this.emit('run_start', singleRunBrowsers)
    }

    if (config.autoWatch) {
      this.on('file_list_modified', () => {
        this.log.debug('List of files has changed, trying to execute')
        if (config.restartOnFileChange) {
          socketServer.sockets.emit('stop')
        }
        executor.schedule()
      })
    }

    processWrapper.on('SIGINT', () => this._close())
    processWrapper.on('SIGTERM', () => this._close())

    const reportError = (error) => {
      this.log.error(error)
      process.emit('infrastructure_error', error)
      this._close(1)
    }

    processWrapper.on('unhandledRejection', (error) => {
      this.log.error(`UnhandledRejection: ${error.stack || error.message || String(error)}`)
      reportError(error)
    })

    processWrapper.on('uncaughtException', (error) => {
      this.log.error(`UncaughtException: ${error.stack || error.message || String(error)}`)
      reportError(error)
    })
  }

  _detach (config, done) {
    const tmpFile = tmp.fileSync({ keep: true })
    this.log.info('Starting karma detached')
    this.log.info('Run "karma stop" to stop the server.')
    this.log.debug(`Writing config to tmp-file ${tmpFile.name}`)
    config.detached = false
    try {
      fs.writeFileSync(tmpFile.name, JSON.stringify(config), 'utf8')
    } catch (e) {
      this.log.error("Couldn't write temporary configuration file")
      done(1)
      return
    }
    const child = spawn(process.argv[0], [path.resolve(__dirname, '../lib/detached.js'), tmpFile.name], {
      detached: true,
      stdio: 'ignore'
    })
    child.unref()
  }

  /**
   * Cleanup all resources allocated by Karma and call the `done` callback
   * with the result of the tests execution.
   *
   * @param [exitCode] - Optional exit code. If omitted will be computed by
   * 'exit' event listeners.
   */
  _close (exitCode) {
    const webServer = this._injector.get('webServer')
    const socketServer = this._injector.get('socketServer')
    const done = this._injector.get('done')

    const webServerCloseTimeout = 3000
    const sockets = socketServer.sockets.sockets

    Object.keys(sockets).forEach((id) => {
      const socket = sockets[id]
      socket.removeAllListeners('disconnect')
      if (!socket.disconnected) {
        process.nextTick(socket.disconnect.bind(socket))
      }
    })

    this.emitExitAsync(exitCode).catch((err) => {
      this.log.error('Error while calling exit event listeners\n' + err.stack || err)
      return 1
    }).then((code) => {
      socketServer.sockets.removeAllListeners()
      socketServer.close()

      let removeAllListenersDone = false
      const removeAllListeners = () => {
        if (removeAllListenersDone) {
          return
        }
        removeAllListenersDone = true
        webServer.removeAllListeners()
        processWrapper.removeAllListeners()
        done(code || 0)
      }

      const closeTimeout = setTimeout(removeAllListeners, webServerCloseTimeout)

      webServer.close(() => {
        clearTimeout(closeTimeout)
        removeAllListeners()
      })
    })
  }

  stop () {
    return this.emitAsync('stop')
  }
}

Server.prototype._start.$inject = ['config', 'launcher', 'preprocess', 'fileList', 'capturedBrowsers', 'executor', 'done']

module.exports = Server
<|endoftext|>


<commit_before>import R from 'ramda';

export default {
  join: (bot, msg, suffix) => {
    if (!suffix) {
      bot.sendMessage(msg.channel, 'Usage: **`!join`** `invitation link`');
      return;
    }
    let invite = msg.content.split(' ')[1];
    bot.joinServer(invite, (err, server) => {
      if (err) {
        bot.sendMessage(msg.channel, `Failed to join: ${err}`);
      } else {
        bot.sendMessage(msg.channel, `Successfully joined ${server}`);
      }
    });
  },
  'join-server': (bot, msg, suffix) => {
    if (!suffix) {
      bot.sendMessage(msg.channel, 'Usage: **`!join-server`** `invitation link`');
      return;
    }
    let invite = msg.content.split(' ')[1];
    bot.joinServer(invite, (err, server) => {
      if (err) {
        bot.sendMessage(msg.channel, `Failed to join: ${err}`);
      } else {
        bot.sendMessage(msg.channel, `Successfully joined ${server}`);
      }
    });
  },
  serverinfo: (bot, msg) => {
    let serverinfo = (`\`\`\`
Server Name: ${msg.channel.server.name}
Server ID: ${msg.channel.server.id}
Server Region: ${msg.channel.server.region}
Server Owner: ${msg.channel.server.owner.username}
Channels: ${msg.channel.server.channels.length}
Default Channel: ${msg.channel.server.defaultChannel.name}
Members: ${msg.channel.server.members.length}
Server Icon: ${msg.channel.server.iconURL}
      \`\`\``);
    bot.sendMessage(msg, serverinfo);
  },
  serverlist: (bot, msg) => {
    let server_list = R.map(server => {
      let online = server.members.reduce((count, member) => count + (member.status === 'online' ? 1 : 0), 0);
      return `**\`${server}\`** ${server.members.length} members (${online} online)`;
    });
    bot.sendMessage(msg.channel, server_list.join('\n'));
  },
  servers: (bot, msg) => {
    bot.sendMessage(msg.channel, `Connected to ${bot.servers.length} servers, ${bot.channels.length} channels and ${bot.users.length} users.`);
  },
  userinfo: (bot, msg, suffix) => {
    if (msg.mentions.length === 0) {
      var userinfo = (`\`\`\`
Name: ${msg.author.username}
ID: ${msg.author.id}
Discriminator: ${msg.author.discriminator}
Status: ${msg.author.status}
Avatar: ${msg.author.avatarURL}
        \`\`\``);
      bot.sendMessage(msg, userinfo);
    } else {
      R.forEach(user => {
        if (user != null) {
          var userinfo = (`\`\`\`
Name: ${user.username}
ID: ${user.id}
Discriminator: ${user.discriminator}
Status: ${user.status}
Avatar: ${user.avatarURL}
            \`\`\``);
          bot.sendMessage(msg, userinfo);
        }
      }, msg.mentions);
    }
  },
  uptime: (bot, msg) => {
    let uptimeh = Math.floor((bot.uptime / 1000) / (60 * 60));
    let uptimem = Math.floor((bot.uptime / 1000) % (60 * 60) / 60);
    let uptimes = Math.floor((bot.uptime / 1000) % 60);
    bot.sendMessage(msg.channel, `I have been alive for:
${uptimeh} Hours
${uptimem} Minutes
${uptimes} Seconds
    `);
  }
};
<commit_msg>fix !serverlist<commit_after>import R from 'ramda';

export default {
  join: (bot, msg, suffix) => {
    if (!suffix) {
      bot.sendMessage(msg.channel, 'Usage: **`!join`** `invitation link`');
      return;
    }
    let invite = msg.content.split(' ')[1];
    bot.joinServer(invite, (err, server) => {
      if (err) {
        bot.sendMessage(msg.channel, `Failed to join: ${err}`);
      } else {
        bot.sendMessage(msg.channel, `Successfully joined ${server}`);
      }
    });
  },
  'join-server': (bot, msg, suffix) => {
    if (!suffix) {
      bot.sendMessage(msg.channel, 'Usage: **`!join-server`** `invitation link`');
      return;
    }
    let invite = msg.content.split(' ')[1];
    bot.joinServer(invite, (err, server) => {
      if (err) {
        bot.sendMessage(msg.channel, `Failed to join: ${err}`);
      } else {
        bot.sendMessage(msg.channel, `Successfully joined ${server}`);
      }
    });
  },
  serverinfo: (bot, msg) => {
    let serverinfo = (`\`\`\`
Server Name: ${msg.channel.server.name}
Server ID: ${msg.channel.server.id}
Server Region: ${msg.channel.server.region}
Server Owner: ${msg.channel.server.owner.username}
Channels: ${msg.channel.server.channels.length}
Default Channel: ${msg.channel.server.defaultChannel.name}
Members: ${msg.channel.server.members.length}
Server Icon: ${msg.channel.server.iconURL}
      \`\`\``);
    bot.sendMessage(msg, serverinfo);
  },
  serverlist: (bot, msg) => {
    let server_list = R.map(server => {
      let online = server.members.reduce((count, member) => count + (member.status === 'online' ? 1 : 0), 0);
      return `**\`${server}\`** ${server.members.length} members (${online} online)`;
    }, bot.servers.sort());
    bot.sendMessage(msg.channel, server_list.join('\n'));
  },
  servers: (bot, msg) => {
    bot.sendMessage(msg.channel, `Connected to ${bot.servers.length} servers, ${bot.channels.length} channels and ${bot.users.length} users.`);
  },
  userinfo: (bot, msg, suffix) => {
    if (msg.mentions.length === 0) {
      var userinfo = (`\`\`\`
Name: ${msg.author.username}
ID: ${msg.author.id}
Discriminator: ${msg.author.discriminator}
Status: ${msg.author.status}
Avatar: ${msg.author.avatarURL}
        \`\`\``);
      bot.sendMessage(msg, userinfo);
    } else {
      R.forEach(user => {
        if (user != null) {
          var userinfo = (`\`\`\`
Name: ${user.username}
ID: ${user.id}
Discriminator: ${user.discriminator}
Status: ${user.status}
Avatar: ${user.avatarURL}
            \`\`\``);
          bot.sendMessage(msg, userinfo);
        }
      }, msg.mentions);
    }
  },
  uptime: (bot, msg) => {
    let uptimeh = Math.floor((bot.uptime / 1000) / (60 * 60));
    let uptimem = Math.floor((bot.uptime / 1000) % (60 * 60) / 60);
    let uptimes = Math.floor((bot.uptime / 1000) % 60);
    bot.sendMessage(msg.channel, `I have been alive for:
${uptimeh} Hours
${uptimem} Minutes
${uptimes} Seconds
    `);
  }
};
<|endoftext|>


<commit_before>/* eslint-disable no-unused-expressions */
import chai, { expect } from 'chai';
import { countOccurences, runSSHCommand } from '../../../utils';
import { describe, it } from 'mocha';
import chaiString from 'chai-string';
import fs from 'fs';
import os from 'os';
import path from 'path';
import sh from 'shelljs';

chai.use(chaiString);

sh.config.silent = false;
const servers = require('../../../../tests/fixtures/servers');

describe('module - default', function() {
  this.timeout(600000);

  describe('deploy', () => {
    it('should deploy meteor app on "meteor" vm', async () => {
      const serverInfo = servers.mymeteor;
      sh.cd(path.resolve(os.tmpdir(), 'tests/project-1'));
      sh.exec('mup setup');

      const out = sh.exec('mup deploy --cached-build');

      expect(out.code).to.equal(0);
      expect(
        out.output
      ).satisfy(text => {
        if (text.indexOf('Building App Bundle Locally') > -1) {
          return true;
        }

        return text.indexOf('Using build from previous deploy at') > -1;
      });

      expect(
        countOccurences(
          'Pushing Meteor App Bundle to the Server: SUCCESS',
          out.output
        )
      ).to.be.equal(1);
      expect(
        countOccurences('Pushing the Startup Script: SUCCESS', out.output)
      ).to.be.equal(1);
      expect(
        countOccurences('Sending Environment Variables: SUCCESS', out.output)
      ).to.be.equal(1);
      expect(countOccurences('Start Meteor: SUCCESS', out.output)).to.be.equal(
        1
      );
      expect(
        countOccurences('Verifying Deployment: SUCCESS', out.output)
      ).to.be.equal(1);
      const ssh1 = await runSSHCommand(
        serverInfo,
        'nc -z -v -w5 localhost 27017'
      );
      expect(ssh1.code).to.be.equal(0);
      const ssh2 = await runSSHCommand(
        serverInfo,
        'curl localhost:80 && exit 0'
      );
      expect(ssh2.code).to.be.equal(0);
    });
  });

  describe('init', () => {
    it('should create "mup.js" and "setting.json" in /tmp/project-tmp', () => {
      const dir = path.resolve(os.tmpdir(), 'project-tmp');
      sh.mkdir(dir);
      sh.cd(dir);
      sh.exec('mup init');
      expect(fs.existsSync(path.resolve(dir, 'mup.js'))).to.true;
      expect(fs.existsSync(path.resolve(dir, 'settings.json'))).to.true;
      sh.rm('-rf', dir);
    });
  });

  describe('logs', () => {
    it('should pull the logs from meteor app', () => {
      sh.cd(path.resolve(os.tmpdir(), 'tests/project-1'));
      const out = sh.exec('mup logs --tail 2');
      expect(out.code).to.be.equal(0);
    });
  });

  describe('reconfig', () => {
    it('should reconfig meteor app on "meteor" vm', async () => {
      const serverInfo = servers.mymeteor;
      sh.cd(path.resolve(os.tmpdir(), 'tests/project-1'));
      sh.exec('mup setup  && mup deploy --cached-build');

      const out = sh.exec('mup reconfig');

      expect(out.code).to.be.equal(0);
      expect(
        countOccurences('Sending Environment Variables: SUCCESS', out.output)
      ).to.be.equal(1);
      expect(countOccurences('Start Meteor: SUCCESS', out.output)).to.be.equal(
        1
      );
      expect(
        countOccurences('Verifying Deployment: SUCCESS', out.output)
      ).to.be.equal(1);
      expect(
        (await runSSHCommand(serverInfo, 'curl localhost:80 && exit 0')).code
      ).to.be.equal(0);
    });
  });

  describe('restart', () => {
    it('should restart meteor app on "meteor" vm', async () => {
      const serverInfo = servers.mymeteor;
      sh.cd(path.resolve(os.tmpdir(), 'tests/project-1'));
      sh.exec('mup setup  && mup deploy --cached-build');

      const out = sh.exec('mup restart');

      expect(out.code).to.be.equal(0);
      expect(out.output).to.have.entriesCount('Stop Meteor: SUCCESS', 1);
      expect(out.output).to.have.entriesCount('Start Meteor: SUCCESS', 1);
      expect(
        out.output
      ).to.have.entriesCount('Verifying Deployment: SUCCESS', 1);
      expect(
        (await runSSHCommand(serverInfo, 'curl localhost:80 && exit 0')).code
      ).to.be.equal(0, 'Curl exit code');
    });
  });

  describe('setup', () => {
    it('should setup "meteor" vm', async () => {
      const serverInfo = servers.mymeteor;
      sh.cd(path.resolve(os.tmpdir(), 'tests/project-1'));

      const out = sh.exec('mup setup');

      expect(out.code).to.be.equal(0);
      expect(countOccurences('Setup Docker: SUCCESS', out.output)).to.be.equal(
        1
      );
      expect(
        countOccurences('Setup Environment: SUCCESS', out.output)
      ).to.be.equal(2);
      expect(countOccurences('Start Mongo: SUCCESS', out.output)).to.be.equal(
        1
      );
      expect(
        (await runSSHCommand(serverInfo, 'nc -z -v -w5 localhost 27017')).code
      ).to.be.equal(0);
    });
  });

  describe('start', () => {
    it('should start meteor app on "meteor" vm', async () => {
      const serverInfo = servers.mymeteor;
      sh.cd(path.resolve(os.tmpdir(), 'tests/project-1'));
      sh.exec('mup setup  && mup meteor push --cached-build && mup meteor envconfig');

      const out = sh.exec('mup start');

      expect(out.code).to.be.equal(0);
      expect(countOccurences('Start Meteor: SUCCESS', out.output)).to.be.equal(
        1
      );
      expect(
        countOccurences('Verifying Deployment: SUCCESS', out.output)
      ).to.be.equal(1);
      expect(
        (await runSSHCommand(serverInfo, 'curl localhost:80 && exit 0')).code
      ).to.be.equal(0);
    });
  });

  describe('stop', () => {
    it('should stop meteor app on "meteor" vm', async () => {
      const serverInfo = servers.mymeteor;
      sh.cd(path.resolve(os.tmpdir(), 'tests/project-1'));
      sh.exec('mup setup  && mup deploy --cached-build');

      const out = sh.exec('mup stop');

      expect(out.code).to.be.equal(0);
      expect(countOccurences('Stop Meteor: SUCCESS', out.output)).to.be.equal(
        1
      );
      expect(
        (await runSSHCommand(serverInfo, 'curl localhost:80 && exit 0')).code
      ).to.be.equal(7);
    });
  });

  describe('syslog', () => {
    const serverInfo = servers.mymeteor;

    it('should write meteor logs to syslog on "meteor" vm', async () => {
      sh.cd(path.resolve(os.tmpdir(), 'tests/project-2'));

      sh.exec('mup setup && mup deploy --cached-build');
      const out = await runSSHCommand(
        serverInfo,
        'sudo tail -n 100 /var/log/syslog'
      );
      expect(out.code).to.be.equal(0);

      expect(
        countOccurences('=> Starting meteor app on port:80', out.output)
      ).gte(1);
    });
  });
});
<commit_msg>Increase test timeout<commit_after>/* eslint-disable no-unused-expressions */
import chai, { expect } from 'chai';
import { countOccurences, runSSHCommand } from '../../../utils';
import { describe, it } from 'mocha';
import chaiString from 'chai-string';
import fs from 'fs';
import os from 'os';
import path from 'path';
import sh from 'shelljs';

chai.use(chaiString);

sh.config.silent = false;
const servers = require('../../../../tests/fixtures/servers');

describe('module - default', function() {
  this.timeout(900000);

  describe('deploy', () => {
    it('should deploy meteor app on "meteor" vm', async () => {
      const serverInfo = servers.mymeteor;
      sh.cd(path.resolve(os.tmpdir(), 'tests/project-1'));
      sh.exec('mup setup');

      const out = sh.exec('mup deploy --cached-build');

      expect(out.code).to.equal(0);
      expect(
        out.output
      ).satisfy(text => {
        if (text.indexOf('Building App Bundle Locally') > -1) {
          return true;
        }

        return text.indexOf('Using build from previous deploy at') > -1;
      });

      expect(
        countOccurences(
          'Pushing Meteor App Bundle to the Server: SUCCESS',
          out.output
        )
      ).to.be.equal(1);
      expect(
        countOccurences('Pushing the Startup Script: SUCCESS', out.output)
      ).to.be.equal(1);
      expect(
        countOccurences('Sending Environment Variables: SUCCESS', out.output)
      ).to.be.equal(1);
      expect(countOccurences('Start Meteor: SUCCESS', out.output)).to.be.equal(
        1
      );
      expect(
        countOccurences('Verifying Deployment: SUCCESS', out.output)
      ).to.be.equal(1);
      const ssh1 = await runSSHCommand(
        serverInfo,
        'nc -z -v -w5 localhost 27017'
      );
      expect(ssh1.code).to.be.equal(0);
      const ssh2 = await runSSHCommand(
        serverInfo,
        'curl localhost:80 && exit 0'
      );
      expect(ssh2.code).to.be.equal(0);
    });
  });

  describe('init', () => {
    it('should create "mup.js" and "setting.json" in /tmp/project-tmp', () => {
      const dir = path.resolve(os.tmpdir(), 'project-tmp');
      sh.mkdir(dir);
      sh.cd(dir);
      sh.exec('mup init');
      expect(fs.existsSync(path.resolve(dir, 'mup.js'))).to.true;
      expect(fs.existsSync(path.resolve(dir, 'settings.json'))).to.true;
      sh.rm('-rf', dir);
    });
  });

  describe('logs', () => {
    it('should pull the logs from meteor app', () => {
      sh.cd(path.resolve(os.tmpdir(), 'tests/project-1'));
      const out = sh.exec('mup logs --tail 2');
      expect(out.code).to.be.equal(0);
    });
  });

  describe('reconfig', () => {
    it('should reconfig meteor app on "meteor" vm', async () => {
      const serverInfo = servers.mymeteor;
      sh.cd(path.resolve(os.tmpdir(), 'tests/project-1'));
      sh.exec('mup setup  && mup deploy --cached-build');

      const out = sh.exec('mup reconfig');

      expect(out.code).to.be.equal(0);
      expect(
        countOccurences('Sending Environment Variables: SUCCESS', out.output)
      ).to.be.equal(1);
      expect(countOccurences('Start Meteor: SUCCESS', out.output)).to.be.equal(
        1
      );
      expect(
        countOccurences('Verifying Deployment: SUCCESS', out.output)
      ).to.be.equal(1);
      expect(
        (await runSSHCommand(serverInfo, 'curl localhost:80 && exit 0')).code
      ).to.be.equal(0);
    });
  });

  describe('restart', () => {
    it('should restart meteor app on "meteor" vm', async () => {
      const serverInfo = servers.mymeteor;
      sh.cd(path.resolve(os.tmpdir(), 'tests/project-1'));
      sh.exec('mup setup  && mup deploy --cached-build');

      const out = sh.exec('mup restart');

      expect(out.code).to.be.equal(0);
      expect(out.output).to.have.entriesCount('Stop Meteor: SUCCESS', 1);
      expect(out.output).to.have.entriesCount('Start Meteor: SUCCESS', 1);
      expect(
        out.output
      ).to.have.entriesCount('Verifying Deployment: SUCCESS', 1);
      expect(
        (await runSSHCommand(serverInfo, 'curl localhost:80 && exit 0')).code
      ).to.be.equal(0, 'Curl exit code');
    });
  });

  describe('setup', () => {
    it('should setup "meteor" vm', async () => {
      const serverInfo = servers.mymeteor;
      sh.cd(path.resolve(os.tmpdir(), 'tests/project-1'));

      const out = sh.exec('mup setup');

      expect(out.code).to.be.equal(0);
      expect(countOccurences('Setup Docker: SUCCESS', out.output)).to.be.equal(
        1
      );
      expect(
        countOccurences('Setup Environment: SUCCESS', out.output)
      ).to.be.equal(2);
      expect(countOccurences('Start Mongo: SUCCESS', out.output)).to.be.equal(
        1
      );
      expect(
        (await runSSHCommand(serverInfo, 'nc -z -v -w5 localhost 27017')).code
      ).to.be.equal(0);
    });
  });

  describe('start', () => {
    it('should start meteor app on "meteor" vm', async () => {
      const serverInfo = servers.mymeteor;
      sh.cd(path.resolve(os.tmpdir(), 'tests/project-1'));
      sh.exec('mup setup  && mup meteor push --cached-build && mup meteor envconfig');

      const out = sh.exec('mup start');

      expect(out.code).to.be.equal(0);
      expect(countOccurences('Start Meteor: SUCCESS', out.output)).to.be.equal(
        1
      );
      expect(
        countOccurences('Verifying Deployment: SUCCESS', out.output)
      ).to.be.equal(1);
      expect(
        (await runSSHCommand(serverInfo, 'curl localhost:80 && exit 0')).code
      ).to.be.equal(0);
    });
  });

  describe('stop', () => {
    it('should stop meteor app on "meteor" vm', async () => {
      const serverInfo = servers.mymeteor;
      sh.cd(path.resolve(os.tmpdir(), 'tests/project-1'));
      sh.exec('mup setup  && mup deploy --cached-build');

      const out = sh.exec('mup stop');

      expect(out.code).to.be.equal(0);
      expect(countOccurences('Stop Meteor: SUCCESS', out.output)).to.be.equal(
        1
      );
      expect(
        (await runSSHCommand(serverInfo, 'curl localhost:80 && exit 0')).code
      ).to.be.equal(7);
    });
  });

  describe('syslog', () => {
    const serverInfo = servers.mymeteor;

    it('should write meteor logs to syslog on "meteor" vm', async () => {
      sh.cd(path.resolve(os.tmpdir(), 'tests/project-2'));

      sh.exec('mup setup && mup deploy --cached-build');
      const out = await runSSHCommand(
        serverInfo,
        'sudo tail -n 100 /var/log/syslog'
      );
      expect(out.code).to.be.equal(0);

      expect(
        countOccurences('=> Starting meteor app on port:80', out.output)
      ).gte(1);
    });
  });
});
<|endoftext|>