<commit_before>/*
* server.js
*
* Resource Server Sample
*
* See README.md for details
*
* Copyright (C) Province of British Columbia, 2013
*/

var express = require('express')
  , app = express()
  , developer = require('./developer')
  , lawyer = require('./lawyer')
  , admin = require('./admin')
  , resource = require('./resource')

var LISTEN_PORT = 9090  // change if you want listen on a different port

if (process.env.DOTCLOUD_WWW_HTTP_URL) {
  // looks like we are running on DotCloud, adjust our world
  LISTEN_PORT = 8080
} else if (process.env.PORT) {
  // HACK! looks like we might be running on Azure
  LISTEN_PORT = process.env.PORT
  //  var AZURE = true
}

// clear session, logout user
function logout ( req, res )  {
  req.session = null
  res.redirect('/')
}

// send a static file
function sendfile ( file ) {
  return function( req, res ) { res.sendfile( __dirname + file ) }
}

// error handler -- gets called if a request processor calls next( Error )
function errorHandler ( error, req, res, next ) {
  if (!error.code) {
    error.code = "UNKNOWN"
    console.error(error.stack)
    res.send({'error':{'code': error.code, 'message': error.message, 'stack': error.stack}})
  } else {
    console.error(error.stack)
    res.send({'error':{'code': error.code, 'message': error.message}})
  }
}

//
// set up middleware
//

app.use( express.static( __dirname + '/html/assets' ) )   // put static assets here
app.use( express.logger( 'dev' ) )                        // so that we only log page requests
app.use( express.limit('10kb') )                          // protect against large POST attack
app.use( express.bodyParser() )

app.use( express.cookieParser('a secret string') )
var cookieOptions =
  { 'secret': 'helloworldsecret'
  , 'cookie': { path: '/' } }
app.use( express.cookieSession( cookieOptions ))

//
// setup request routes
//

// these end points are all AJAX calls from the web app and return a JSON response
app.post('/lawyer/login/QR', lawyer.loginQR )
app.post('/lawyer/profile', lawyer.profile )
app.post('/lawyer/agree/tos', lawyer.agreeTOS )
app.post('/lawyer/status', lawyer.status )
app.post('/lawyer/check/QR', lawyer.checkQR )

app.post('/developer/login/QR', developer.loginQR )
app.post('/developer/check/QR', developer.checkQR )
app.post('/developer/login/check', developer.loginCheck )

app.post('/admin/login/QR', admin.loginQR )
app.post('/admin/check/QR', admin.checkQR )

// these pages are called by either the Agent or a QR Code reader
// returns either the Agent Request in JSON if called by Agent
// or sends a redirect to the a2p3.net://token URL
// also called by the Agent via the notification URL mechanism
app.get('/lawyer/QR/:qrSession', lawyer.qrCode )
app.get('/developer/QR/:qrSession', developer.qrCode )
app.get('/admin/QR/:qrSession', admin.qrCode )

//
// these pages all return a redirect
//
app.get('/logout', logout)

// called if App and Agent are on same device
app.get('/lawyer/login/direct', lawyer.loginDirect )
app.get('/lawyer/response/redirect', lawyer.loginResponseRedirect )
app.get('/lawyer/account/delete', lawyer.accountDelete )

app.get('/developer/login/direct', developer.loginDirect )
app.get('/developer/response/redirect', developer.loginResponseRedirect )

app.get('/admin/login/direct', admin.loginDirect )
app.get('/admin/response/redirect', admin.loginResponseRedirect )

// called if App and Agent are on different devices
app.post('/lawyer/response/callback', lawyer.loginResponseCallback )
app.post('/developer/response/callback', developer.loginResponseCallback )
app.post('/admin/response/callback', admin.loginResponseCallback )

//
// these endpoints serve static HTML pages
//
app.get('/',                sendfile( '/html/index.html' ) )
app.get('/error',           sendfile( '/html/error.html' ) )
app.get('/agent/install',   sendfile( '/html/agent_install.html' ) )

app.get('/lawyer',          sendfile( '/html/lawyer.html' )  )
app.get('/dashboard',       sendfile( '/html/developer.html' )  ) // URL used in scripts that register apps
app.get('/developer',       sendfile( '/html/developer.html' )  )
app.get('/admin',           sendfile( '/html/admin.html' )  )

//
//  Resource Server API end points
//

// Standard App Registration end points so that Sample App can register with CLI
app.get('/login',                   developer.loginDirect )
app.post('/dashboard/new/app',      developer.newApp )
app.post('/dashboard/app/details',  developer.appDetails )
app.post('/dashboard/list/apps',    developer.listApps )
app.post('/dashboard/delete/app',   developer.deleteApp )
app.post('/dashboard/refresh/key',  developer.refreshKey )
app.post('/dashboard/getkey',       developer.getkey )

// admin APIs
app.post('/admin/memberships', admin.memberships )
app.post('/admin/membershipStatus', admin.membershipStatus )
app.post('/admin/applications', admin.applications )

// resource APIs
app.post('/membership/status', resource.membershipStatus() )
app.post('/membership/number', resource.membershipNumber() )
app.post('/membership/anytime/status', resource.membershipAnytimeStatus() )
app.post('/membership/anytime/number', resource.membershipAnytimeNumber() )

app.post('/oauth', resource.oauth() )

app.post('/authorizations/list', resource.AuthorizationsList() )
app.post('/authorizations/Delete', resource.AuthorizationsDelete() )

app.get('/documentation', resource.documentation )
app.get(/\/scope[\w\/]*/, resource.scopes )

app.use( errorHandler )

app.listen( LISTEN_PORT )

console.log('\nSample RS available on this machine on port:', LISTEN_PORT )

// console.log('\nprocess.env dump\n',process.env)
<commit_msg>reverted accidental commit of server.js<commit_after>/*
* server.js
*
* Resource Server Sample
*
* See README.md for details
*
* Copyright (C) Province of British Columbia, 2013
*/

var express = require('express')
  , app = express()
  , developer = require('./developer')
  , lawyer = require('./lawyer')
  , admin = require('./admin')
  , resource = require('./resource')

var LISTEN_PORT = 8080  // change if you want listen on a different port

if (process.env.DOTCLOUD_WWW_HTTP_URL) {
  // looks like we are running on DotCloud, adjust our world
  LISTEN_PORT = 8080
} else if (process.env.PORT) {
  // HACK! looks like we might be running on Azure
  LISTEN_PORT = process.env.PORT
  //  var AZURE = true
}

// clear session, logout user
function logout ( req, res )  {
  req.session = null
  res.redirect('/')
}

// send a static file
function sendfile ( file ) {
  return function( req, res ) { res.sendfile( __dirname + file ) }
}

// error handler -- gets called if a request processor calls next( Error )
function errorHandler ( error, req, res, next ) {
  if (!error.code) {
    error.code = "UNKNOWN"
    console.error(error.stack)
    res.send({'error':{'code': error.code, 'message': error.message, 'stack': error.stack}})
  } else {
    console.error(error.stack)
    res.send({'error':{'code': error.code, 'message': error.message}})
  }
}

//
// set up middleware
//

app.use( express.static( __dirname + '/html/assets' ) )   // put static assets here
app.use( express.logger( 'dev' ) )                        // so that we only log page requests
app.use( express.limit('10kb') )                          // protect against large POST attack
app.use( express.bodyParser() )

app.use( express.cookieParser('a secret string') )
var cookieOptions =
  { 'secret': 'helloworldsecret'
  , 'cookie': { path: '/' } }
app.use( express.cookieSession( cookieOptions ))

//
// setup request routes
//

// these end points are all AJAX calls from the web app and return a JSON response
app.post('/lawyer/login/QR', lawyer.loginQR )
app.post('/lawyer/profile', lawyer.profile )
app.post('/lawyer/agree/tos', lawyer.agreeTOS )
app.post('/lawyer/status', lawyer.status )
app.post('/lawyer/check/QR', lawyer.checkQR )

app.post('/developer/login/QR', developer.loginQR )
app.post('/developer/check/QR', developer.checkQR )
app.post('/developer/login/check', developer.loginCheck )

app.post('/admin/login/QR', admin.loginQR )
app.post('/admin/check/QR', admin.checkQR )

// these pages are called by either the Agent or a QR Code reader
// returns either the Agent Request in JSON if called by Agent
// or sends a redirect to the a2p3.net://token URL
// also called by the Agent via the notification URL mechanism
app.get('/lawyer/QR/:qrSession', lawyer.qrCode )
app.get('/developer/QR/:qrSession', developer.qrCode )
app.get('/admin/QR/:qrSession', admin.qrCode )

//
// these pages all return a redirect
//
app.get('/logout', logout)

// called if App and Agent are on same device
app.get('/lawyer/login/direct', lawyer.loginDirect )
app.get('/lawyer/response/redirect', lawyer.loginResponseRedirect )
app.get('/lawyer/account/delete', lawyer.accountDelete )

app.get('/developer/login/direct', developer.loginDirect )
app.get('/developer/response/redirect', developer.loginResponseRedirect )

app.get('/admin/login/direct', admin.loginDirect )
app.get('/admin/response/redirect', admin.loginResponseRedirect )

// called if App and Agent are on different devices
app.post('/lawyer/response/callback', lawyer.loginResponseCallback )
app.post('/developer/response/callback', developer.loginResponseCallback )
app.post('/admin/response/callback', admin.loginResponseCallback )

//
// these endpoints serve static HTML pages
//
app.get('/',                sendfile( '/html/index.html' ) )
app.get('/error',           sendfile( '/html/error.html' ) )
app.get('/agent/install',   sendfile( '/html/agent_install.html' ) )

app.get('/lawyer',          sendfile( '/html/lawyer.html' )  )
app.get('/dashboard',       sendfile( '/html/developer.html' )  ) // URL used in scripts that register apps
app.get('/developer',       sendfile( '/html/developer.html' )  )
app.get('/admin',           sendfile( '/html/admin.html' )  )

//
//  Resource Server API end points
//

// Standard App Registration end points so that Sample App can register with CLI
app.get('/login',                   developer.loginDirect )
app.post('/dashboard/new/app',      developer.newApp )
app.post('/dashboard/app/details',  developer.appDetails )
app.post('/dashboard/list/apps',    developer.listApps )
app.post('/dashboard/delete/app',   developer.deleteApp )
app.post('/dashboard/refresh/key',  developer.refreshKey )
app.post('/dashboard/getkey',       developer.getkey )

// admin APIs
app.post('/admin/memberships', admin.memberships )
app.post('/admin/membershipStatus', admin.membershipStatus )
app.post('/admin/applications', admin.applications )

// resource APIs
app.post('/membership/status', resource.membershipStatus() )
app.post('/membership/number', resource.membershipNumber() )
app.post('/membership/anytime/status', resource.membershipAnytimeStatus() )
app.post('/membership/anytime/number', resource.membershipAnytimeNumber() )

app.post('/oauth', resource.oauth() )

app.post('/authorizations/list', resource.AuthorizationsList() )
app.post('/authorizations/Delete', resource.AuthorizationsDelete() )

app.get('/documentation', resource.documentation )
app.get(/\/scope[\w\/]*/, resource.scopes )

app.use( errorHandler )

app.listen( LISTEN_PORT )

console.log('\nSample RS available on this machine on port:', LISTEN_PORT )

// console.log('\nprocess.env dump\n',process.env)
<|endoftext|>


<commit_before>/*
    globals require console
*/
var Express = require('express');
var Http = require('http');
var Https = require('https');
var Fs = require('fs');
var WebSocketServer = require('ws').Server;
var NetfluxSrv = require('./node_modules/chainpad-server/NetfluxWebsocketSrv');
var Package = require('./package.json');
var Path = require("path");

var config = require('./config');
var websocketPort = config.websocketPort || config.httpPort;
var useSecureWebsockets = config.useSecureWebsockets || false;

// support multiple storage back ends
var Storage = require(config.storage||'./storage/file');

var app = Express();

var httpsOpts;

var DEV_MODE = !!process.env.DEV
if (DEV_MODE) {
    console.log("DEV MODE ENABLED");
}

const clone = (x) => (JSON.parse(JSON.stringify(x)));

var setHeaders = (function () {
    if (typeof(config.httpHeaders) !== 'object') { return function () {}; }

    const headers = clone(config.httpHeaders);
    if (config.contentSecurity) {
        headers['Content-Security-Policy'] = clone(config.contentSecurity);
        if (headers['Content-Security-Policy'].indexOf('frame-ancestors') === -1) {
            // backward compat for those who do not merge the new version of the config
            // when updating. This prevents endless spinner if someone clicks donate.
            headers['Content-Security-Policy'] += "frame-ancestors 'self' accounts.cryptpad.fr;";
        }
    }
    const padHeaders = clone(headers);
    if (config.padContentSecurity) {
        padHeaders['Content-Security-Policy'] = clone(config.padContentSecurity);
    }
    if (Object.keys(headers).length) {
        return function (req, res) {
            const h = /^\/pad\/inner\.html.*/.test(req.url) ? padHeaders : headers;
            for (let header in h) { res.setHeader(header, h[header]); }
        };
    }
    return function () {};
}());

(function () {
if (!config.logFeedback) { return; }

const logFeedback = function (url) {
    url.replace(/\?(.*?)=/, function (all, fb) {
        console.log('[FEEDBACK] %s', fb);
    });
};

app.head(/^\/common\/feedback\.html/, function (req, res, next) {
    logFeedback(req.url);
    next();
});
}());

app.use(function (req, res, next) {
    setHeaders(req, res);
    if (/[\?\&]ver=[^\/]+$/.test(req.url)) { res.setHeader("Cache-Control", "max-age=31536000"); }
    next();
});

app.use(Express.static(__dirname + '/www'));

Fs.exists(__dirname + "/customize", function (e) {
    if (e) { return; }
    console.log("Cryptpad is customizable, see customize.dist/readme.md for details");
});

// FIXME I think this is a regression caused by a recent PR
// correct this hack without breaking the contributor's intended behaviour.

var mainPages = config.mainPages || ['index', 'privacy', 'terms', 'about', 'contact'];
var mainPagePattern = new RegExp('^\/(' + mainPages.join('|') + ').html$');
app.get(mainPagePattern, Express.static(__dirname + '/customize.dist'));

app.use("/blob", Express.static(Path.join(__dirname, (config.blobPath || './blob'))));

app.use("/customize", Express.static(__dirname + '/customize'));
app.use("/customize", Express.static(__dirname + '/customize.dist'));
app.use(/^\/[^\/]*$/, Express.static('customize'));
app.use(/^\/[^\/]*$/, Express.static('customize.dist'));

if (config.privKeyAndCertFiles) {
    var privKeyAndCerts = '';
    config.privKeyAndCertFiles.forEach(function (file) {
        privKeyAndCerts = privKeyAndCerts + Fs.readFileSync(file);
    });
    var array = privKeyAndCerts.split('\n-----BEGIN ');
    for (var i = 1; i < array.length; i++) { array[i] = '-----BEGIN ' + array[i]; }
    var privKey;
    for (var i = 0; i < array.length; i++) {
        if (array[i].indexOf('PRIVATE KEY-----\n') !== -1) {
            privKey = array[i];
            array.splice(i, 1);
            break;
        }
    }
    if (!privKey) { throw new Error("cannot find private key"); }
    httpsOpts = {
        cert: array.shift(),
        key: privKey,
        ca: array
    };
}

app.get('/api/config', function(req, res){
    var host = req.headers.host.replace(/\:[0-9]+/, '');
    res.setHeader('Content-Type', 'text/javascript');
    res.send('define(' + JSON.stringify({
        requireConf: {
            waitSeconds: 60,
            urlArgs: 'ver=' + Package.version + (DEV_MODE? '-' + (+new Date()): ''),
        },
        removeDonateButton: (config.removeDonateButton === true),
        allowSubscriptions: (config.allowSubscriptions === true),

        websocketPath: config.useExternalWebsocket ? undefined : config.websocketPath,
        websocketURL:'ws' + ((useSecureWebsockets) ? 's' : '') + '://' + host + ':' +
            websocketPort + '/cryptpad_websocket',
    }) + ');');
});

var httpServer = httpsOpts ? Https.createServer(httpsOpts, app) : Http.createServer(app);

httpServer.listen(config.httpPort,config.httpAddress,function(){
    var host = config.httpAddress;
    var hostName = !host.indexOf(':') ? '[' + host + ']' : host;

    var port = config.httpPort;
    var ps = port === 80? '': ':' + port;

    console.log('\n[%s] server available http://%s%s', new Date().toISOString(), hostName, ps);
});

var wsConfig = { server: httpServer };

var createSocketServer = function (err, rpc) {
    if(!config.useExternalWebsocket) {
        if (websocketPort !== config.httpPort) {
            console.log("setting up a new websocket server");
            wsConfig = { port: websocketPort};
        }
        var wsSrv = new WebSocketServer(wsConfig);
        Storage.create(config, function (store) {
            NetfluxSrv.run(store, wsSrv, config, rpc);
        });
    }
};

var loadRPC = function (cb) {
    config.rpc = typeof(config.rpc) === 'undefined'? './rpc.js' : config.rpc;

    if (typeof(config.rpc) === 'string') {
        // load pin store...
        var Rpc = require(config.rpc);
        Rpc.create(config, function (e, rpc) {
            if (e) { throw e; }
            cb(void 0, rpc);
        });
    } else {
        cb();
    }
};

loadRPC(createSocketServer);
<commit_msg>Add a semicolon at the end of the CSP if none exists.<commit_after>/*
    globals require console
*/
var Express = require('express');
var Http = require('http');
var Https = require('https');
var Fs = require('fs');
var WebSocketServer = require('ws').Server;
var NetfluxSrv = require('./node_modules/chainpad-server/NetfluxWebsocketSrv');
var Package = require('./package.json');
var Path = require("path");

var config = require('./config');
var websocketPort = config.websocketPort || config.httpPort;
var useSecureWebsockets = config.useSecureWebsockets || false;

// support multiple storage back ends
var Storage = require(config.storage||'./storage/file');

var app = Express();

var httpsOpts;

var DEV_MODE = !!process.env.DEV
if (DEV_MODE) {
    console.log("DEV MODE ENABLED");
}

const clone = (x) => (JSON.parse(JSON.stringify(x)));

var setHeaders = (function () {
    if (typeof(config.httpHeaders) !== 'object') { return function () {}; }

    const headers = clone(config.httpHeaders);
    if (config.contentSecurity) {
        headers['Content-Security-Policy'] = clone(config.contentSecurity);
        if (!/;$/.test(headers['Content-Security-Policy'])) { headers['Content-Security-Policy'] += ';' }
        if (headers['Content-Security-Policy'].indexOf('frame-ancestors') === -1) {
            // backward compat for those who do not merge the new version of the config
            // when updating. This prevents endless spinner if someone clicks donate.
            headers['Content-Security-Policy'] += "frame-ancestors 'self' accounts.cryptpad.fr;";
        }
    }
    const padHeaders = clone(headers);
    if (config.padContentSecurity) {
        padHeaders['Content-Security-Policy'] = clone(config.padContentSecurity);
    }
    if (Object.keys(headers).length) {
        return function (req, res) {
            const h = /^\/pad\/inner\.html.*/.test(req.url) ? padHeaders : headers;
            for (let header in h) { res.setHeader(header, h[header]); }
        };
    }
    return function () {};
}());

(function () {
if (!config.logFeedback) { return; }

const logFeedback = function (url) {
    url.replace(/\?(.*?)=/, function (all, fb) {
        console.log('[FEEDBACK] %s', fb);
    });
};

app.head(/^\/common\/feedback\.html/, function (req, res, next) {
    logFeedback(req.url);
    next();
});
}());

app.use(function (req, res, next) {
    setHeaders(req, res);
    if (/[\?\&]ver=[^\/]+$/.test(req.url)) { res.setHeader("Cache-Control", "max-age=31536000"); }
    next();
});

app.use(Express.static(__dirname + '/www'));

Fs.exists(__dirname + "/customize", function (e) {
    if (e) { return; }
    console.log("Cryptpad is customizable, see customize.dist/readme.md for details");
});

// FIXME I think this is a regression caused by a recent PR
// correct this hack without breaking the contributor's intended behaviour.

var mainPages = config.mainPages || ['index', 'privacy', 'terms', 'about', 'contact'];
var mainPagePattern = new RegExp('^\/(' + mainPages.join('|') + ').html$');
app.get(mainPagePattern, Express.static(__dirname + '/customize.dist'));

app.use("/blob", Express.static(Path.join(__dirname, (config.blobPath || './blob'))));

app.use("/customize", Express.static(__dirname + '/customize'));
app.use("/customize", Express.static(__dirname + '/customize.dist'));
app.use(/^\/[^\/]*$/, Express.static('customize'));
app.use(/^\/[^\/]*$/, Express.static('customize.dist'));

if (config.privKeyAndCertFiles) {
    var privKeyAndCerts = '';
    config.privKeyAndCertFiles.forEach(function (file) {
        privKeyAndCerts = privKeyAndCerts + Fs.readFileSync(file);
    });
    var array = privKeyAndCerts.split('\n-----BEGIN ');
    for (var i = 1; i < array.length; i++) { array[i] = '-----BEGIN ' + array[i]; }
    var privKey;
    for (var i = 0; i < array.length; i++) {
        if (array[i].indexOf('PRIVATE KEY-----\n') !== -1) {
            privKey = array[i];
            array.splice(i, 1);
            break;
        }
    }
    if (!privKey) { throw new Error("cannot find private key"); }
    httpsOpts = {
        cert: array.shift(),
        key: privKey,
        ca: array
    };
}

app.get('/api/config', function(req, res){
    var host = req.headers.host.replace(/\:[0-9]+/, '');
    res.setHeader('Content-Type', 'text/javascript');
    res.send('define(' + JSON.stringify({
        requireConf: {
            waitSeconds: 60,
            urlArgs: 'ver=' + Package.version + (DEV_MODE? '-' + (+new Date()): ''),
        },
        removeDonateButton: (config.removeDonateButton === true),
        allowSubscriptions: (config.allowSubscriptions === true),

        websocketPath: config.useExternalWebsocket ? undefined : config.websocketPath,
        websocketURL:'ws' + ((useSecureWebsockets) ? 's' : '') + '://' + host + ':' +
            websocketPort + '/cryptpad_websocket',
    }) + ');');
});

var httpServer = httpsOpts ? Https.createServer(httpsOpts, app) : Http.createServer(app);

httpServer.listen(config.httpPort,config.httpAddress,function(){
    var host = config.httpAddress;
    var hostName = !host.indexOf(':') ? '[' + host + ']' : host;

    var port = config.httpPort;
    var ps = port === 80? '': ':' + port;

    console.log('\n[%s] server available http://%s%s', new Date().toISOString(), hostName, ps);
});

var wsConfig = { server: httpServer };

var createSocketServer = function (err, rpc) {
    if(!config.useExternalWebsocket) {
        if (websocketPort !== config.httpPort) {
            console.log("setting up a new websocket server");
            wsConfig = { port: websocketPort};
        }
        var wsSrv = new WebSocketServer(wsConfig);
        Storage.create(config, function (store) {
            NetfluxSrv.run(store, wsSrv, config, rpc);
        });
    }
};

var loadRPC = function (cb) {
    config.rpc = typeof(config.rpc) === 'undefined'? './rpc.js' : config.rpc;

    if (typeof(config.rpc) === 'string') {
        // load pin store...
        var Rpc = require(config.rpc);
        Rpc.create(config, function (e, rpc) {
            if (e) { throw e; }
            cb(void 0, rpc);
        });
    } else {
        cb();
    }
};

loadRPC(createSocketServer);
<|endoftext|>


<commit_before>'use strict';

/**
 * Load Test a URL, website or websocket.
 * (C) 2013 Alex Fernández.
 */

// requires
var WebSocketClient = require('websocket').client;
var urlLib = require('url');
var http = require('http');
var Log = require('log');
var prototypes = require('./prototypes.js');
var timing = require('./timing.js');

// globals
var log = new Log('info');
var latency;
var requests = 0;

// constants
var DEFAULT_OPTIONS = {
	noAgent: true,
	concurrency: 1,
	requestsPerSecond: 1,
};

/**
 * A client for an HTTP connection.
 * Params is an object which must contain:
 *	- url: destination URL.
 *	- requestsPerSecond: how many requests to create from this client.
 * Params may have:
 *	- method: HTTP method (default GET).
 *	- payload: contents of request (default empty).
 *	- maxRequests: stop sending requests after this global limit is reached
 *	(default unlimited).
 *	- maxSeconds: stop receiving requests after this number of seconds
 *	(default unlimited).
 *	- noAgent: if true, do not use connection keep-alive (default false).
 */
function HttpClient(params)
{
	// self-reference
	var self = this;

	// attributes
	var connection;
	var lastCall;
	var timer;

	/**
	 * Start the HTTP client.
	 */
	self.start = function()
	{
		if (!params.requestsPerSecond)
		{
			log.error('No requests per second selected');
			return;
		}
		var interval = Math.round(1000 / params.requestsPerSecond);
		timer = new timing.HighResolutionTimer(interval, self.makeRequest);
	}

	/**
	 * Stop the HTTP client.
	 */
	self.stop = function()
	{
		timer.stop();
	}

	/**
	 * Make a single request to the server.
	 */
	self.makeRequest = function(callback)
	{
		requests += 1;
		if (requests > params.maxRequests)
		{
			if (callback)
			{
				callback(null);
			}
			return timer.stop();
		}
		var id = latency.start(id);
		var options = urlLib.parse(params.url);
		if (params.noAgent)
		{
			options.agent = false;
		}
		if (params.method)
		{
			options.method = params.method;
		}
		var message;
		if (params.payload)
		{
			var message;
			if (typeof params.payload == 'string')
			{
				message = params.payload;
			}
			else if (typeof params.payload == 'object')
			{
				message = JSON.stringify(params.payload);
			}
			else
			{
				log.error('Unrecognized payload: %s', typeof params.payload);
			}
			options.headers = {
				'Content-Length': message.length,
			};
		}
		var request = http.request(options, getConnect(id, function(error, result)
		{
			if (error)
			{
				log.error('Connection %s failed: %s', id, error);
			}
			else
			{
				log.debug('Connection %s ended', id);
			}
			latency.end(id);
			if (callback)
			{
				callback(error, result);
			}
		}));
		if (message)
		{
			request.write(message);
		}
		request.on('error', function(error)
		{
			log.error('Error: %s', error.message);
		});
		request.end();
	}

	/**
	 * Get a function to connect the player.
	 */
	function getConnect(id, callback)
	{
		return function(connection)
		{
			log.debug('HTTP client connected to %s with id %s', params.url, id);
			connection.setEncoding('utf8');
			connection.on('data', function(chunk)
			{
				log.debug('Body: %s', chunk);
			});
			connection.on('error', function(error)
			{
				callback('Connection ' + id + ' failed: ' + error);

			});
			connection.on('end', function(result)
			{
				if (connection.statusCode >= 300)
				{
					return callback('Status code ' + connection.statusCode);
				}
				callback(null, false);
			});
		};
	}
}

/**
 * A client that connects to a websocket.
 */
function WebsocketClient(url, requestsPerSecond)
{
	// self-reference
	var self = this;

	// attributes
	var connection;
	var lastCall;

	/**
	 * Start the websocket client.
	 */
	self.start = function()
	{
		var client = new WebSocketClient();
		client.on('connectFailed', function(error) {
				error('Connect Error: ' + error.toString());
		});
		client.on('connect', connect);
		client.connect(url, []);
		log.debug('WebSocket client connected to ' + url);
	}

	/**
	 * Connect the player.
	 */
	function connect(localConnection)
	{
		connection = localConnection;
		connection.on('error', function(error) {
				error("Connection error: " + error.toString());
		});
		connection.on('close', function() {
				log.debug('Connection closed');
		});
		connection.on('message', function(message) {
				if (message.type != 'utf8')
				{
					error('Invalid message type ' + message.type);
					return;
				}
				if (lastCall)
				{
					var newCall = new Date().getTime();
					latency.add(newCall - lastCall);
					entry += ', latency: ' + (newCall - lastCall);
					lastCall = null;
				}
				var json;
				try
				{
					json = JSON.parse(message.utf8Data);
				}
				catch(e)
				{
					error('Invalid JSON: ' + message.utf8Data);
					return;
				}
				receive(json);
		});

	}

	/**
	 * Receive a message from the server.
	 */
	function receive(message)
	{
		if (!message || !message.type)
		{
			error('Wrong message ' + JSON.stringify(message));
			return;
		}
		if (message.type == 'start')
		{
			log.debug('Starting game for ' + self.playerId);
			setInterval(requestUpdate, Math.round(1000 / requestsPerSecond));
			return;
		}
		if (message.requestId)
		{
			latency.end(message.requestId);
		}
	}

	/**
	 * Request an update from the server.
	 */
	function requestUpdate()
	{
		if (connection.connected)
		{
			var update = {
				requestId: Math.floor(Math.random() * 0x100000000).toString(16),
				type: 'ping',
			};
			connection.sendUTF(JSON.stringify(update));
			latency.start(update.requestId);
		}
	}
}

/**
 * Run a load test.
 * Options is an object which may have:
 *	- url: mandatory URL to access.
 *	- concurrency: how many concurrent clients to use.
 *	- requestsPerSecond: how many requests per second per client.
 *	- maxRequests: how many requests to send
 *	- maxSeconds: how long to run the tests.
 *	- noAgent: if true, then do not use connection keep-alive.
 * An optional callback will be called if/when the test finishes.
 */
exports.loadTest = function(options, callback)
{
	var constructor;
	if (!options.url)
	{
		log.error('Missing URL in options');
		return;
	}
	if (options.url.startsWith('ws://'))
	{
		constructor = function(params)
		{
			return new WebsocketClient(params.url, params.requestsPerSecond);
		};
	}
	else if (options.url.startsWith('http'))
	{
		constructor = function(params)
		{
			return new HttpClient(params);
		};
	}
	else
	{
		return help();
	}
	if (callback)
	{
		options.callback = callback;
	}
	latency = new timing.Latency(options);
	startClients(options, constructor);
}

/**
 * Start a number of measuring clients.
 */
function startClients(options, constructor)
{
	var clients = {};
	var url = options.url;
	for (var index = 0; index < options.concurrency; index++)
	{
		if (options.indexParam)
		{
			options.url = url.replaceAll(indexParam, index);
		}
		clients[index] = constructor(options);
		// start each client 100 ms after the last
		setTimeout(clients[index].start, (index * 100) % 1000);
	}
	if (options.maxSeconds)
	{
		setTimeout(getClientStopper(clients), options.maxSeconds * 1000);
	}
}

/**
 * Get a function that stops all clients.
 */
var getClientStopper = function(clients)
{
	return function()
	{
		for (var index in clients)
		{
			clients[index].stop();
		}
	};
}

/**
 * Display online help.
 */
function help()
{
	console.log('Usage: loadtest [options] URL');
	console.log('  where URL can be a regular HTTP or websocket URL.');
	console.log('Options are:');
	console.log('    -n requests     Number of requests to perform');
	console.log('    -c concurrency  Number of multiple requests to make');
	console.log('    -t timelimit    Seconds to max. wait for responses');
	console.log('    --rps           Requests per second for each client');
	console.log('    --noagent       Do not use http agent (default)');
	console.log('    --agent         Use http agent (Connection: keep-alive)');
	console.log('    --index param   Replace the value of param with an index in the URL');
}

/**
 * Parse one argument and change options accordingly.
 * Returns true if there may be more arguments to parse.
 */
function parseArgument(args, options)
{
	if (args.length <= 1)
	{
		return false;
	}
	if (!args[0].startsWith('-'))
	{
		return false;
	}
	// consume the argument
	var argument = args.shift();
	switch(argument)
	{
		case '-n':
			options.maxRequests = args.shift();
			return true;
		case '-c':
			options.concurrency = args.shift();
			return true;
		case '-t':
			options.maxSeconds = args.shift();
			return true;
		case '--rps':
			options.requestsPerSecond = args.shift();
			return true;
		case '--noagent':
			return true;
		case '--agent':
			options.noAgent = false;
			return true;
	}
	console.error('Unknown option %s', argument);
	return false;
}

/**
 * Process command line arguments and run
 */
exports.run = function(args)
{
	var options = DEFAULT_OPTIONS;
	while (parseArgument(args, options))
	{
	}
	if (args.length != 1)
	{
		if (args.length == 0)
		{
			console.error('Missing URL');
		}
		else
		{
			console.error('Unknown arguments %s', JSON.stringify(args));
		}
		return help();
	}
	options.url = args[0];
	exports.loadTest(options);
}

// start load test if invoked directly
if (__filename == process.argv[1])
{
	exports.run(process.argv.slice(2));
}

<commit_msg>Comment.<commit_after>'use strict';

/**
 * Load Test a URL, website or websocket.
 * (C) 2013 Alex Fernández.
 */

// requires
var WebSocketClient = require('websocket').client;
var urlLib = require('url');
var http = require('http');
var Log = require('log');
var prototypes = require('./prototypes.js');
var timing = require('./timing.js');

// globals
var log = new Log('info');
var latency;
var requests = 0;

// constants
var DEFAULT_OPTIONS = {
	noAgent: true,
	concurrency: 1,
	requestsPerSecond: 1,
};

/**
 * A client for an HTTP connection.
 * Params is an object which must contain:
 *	- url: destination URL.
 *	- requestsPerSecond: how many requests to create from this client.
 * Params may have:
 *	- method: HTTP method (default GET).
 *	- payload: contents of request (default empty).
 *	- maxRequests: stop sending requests after this global limit is reached.
 *	- requestsPerSecond: limit requests per second to send.
 *	- maxSeconds: stop receiving requests after this number of seconds.
 *	- noAgent: if true, do not use connection keep-alive (default false).
 */
function HttpClient(params)
{
	// self-reference
	var self = this;

	// attributes
	var connection;
	var lastCall;
	var timer;

	/**
	 * Start the HTTP client.
	 */
	self.start = function()
	{
		if (!params.requestsPerSecond)
		{
			log.error('No requests per second selected');
			return;
		}
		var interval = Math.round(1000 / params.requestsPerSecond);
		timer = new timing.HighResolutionTimer(interval, self.makeRequest);
	}

	/**
	 * Stop the HTTP client.
	 */
	self.stop = function()
	{
		timer.stop();
	}

	/**
	 * Make a single request to the server.
	 */
	self.makeRequest = function(callback)
	{
		requests += 1;
		if (requests > params.maxRequests)
		{
			if (callback)
			{
				callback(null);
			}
			return timer.stop();
		}
		var id = latency.start(id);
		var options = urlLib.parse(params.url);
		if (params.noAgent)
		{
			options.agent = false;
		}
		if (params.method)
		{
			options.method = params.method;
		}
		var message;
		if (params.payload)
		{
			var message;
			if (typeof params.payload == 'string')
			{
				message = params.payload;
			}
			else if (typeof params.payload == 'object')
			{
				message = JSON.stringify(params.payload);
			}
			else
			{
				log.error('Unrecognized payload: %s', typeof params.payload);
			}
			options.headers = {
				'Content-Length': message.length,
			};
		}
		var request = http.request(options, getConnect(id, function(error, result)
		{
			if (error)
			{
				log.error('Connection %s failed: %s', id, error);
			}
			else
			{
				log.debug('Connection %s ended', id);
			}
			latency.end(id);
			if (callback)
			{
				callback(error, result);
			}
		}));
		if (message)
		{
			request.write(message);
		}
		request.on('error', function(error)
		{
			log.error('Error: %s', error.message);
		});
		request.end();
	}

	/**
	 * Get a function to connect the player.
	 */
	function getConnect(id, callback)
	{
		return function(connection)
		{
			log.debug('HTTP client connected to %s with id %s', params.url, id);
			connection.setEncoding('utf8');
			connection.on('data', function(chunk)
			{
				log.debug('Body: %s', chunk);
			});
			connection.on('error', function(error)
			{
				callback('Connection ' + id + ' failed: ' + error);

			});
			connection.on('end', function(result)
			{
				if (connection.statusCode >= 300)
				{
					return callback('Status code ' + connection.statusCode);
				}
				callback(null, false);
			});
		};
	}
}

/**
 * A client that connects to a websocket.
 */
function WebsocketClient(url, requestsPerSecond)
{
	// self-reference
	var self = this;

	// attributes
	var connection;
	var lastCall;

	/**
	 * Start the websocket client.
	 */
	self.start = function()
	{
		var client = new WebSocketClient();
		client.on('connectFailed', function(error) {
				error('Connect Error: ' + error.toString());
		});
		client.on('connect', connect);
		client.connect(url, []);
		log.debug('WebSocket client connected to ' + url);
	}

	/**
	 * Connect the player.
	 */
	function connect(localConnection)
	{
		connection = localConnection;
		connection.on('error', function(error) {
				error("Connection error: " + error.toString());
		});
		connection.on('close', function() {
				log.debug('Connection closed');
		});
		connection.on('message', function(message) {
				if (message.type != 'utf8')
				{
					error('Invalid message type ' + message.type);
					return;
				}
				if (lastCall)
				{
					var newCall = new Date().getTime();
					latency.add(newCall - lastCall);
					entry += ', latency: ' + (newCall - lastCall);
					lastCall = null;
				}
				var json;
				try
				{
					json = JSON.parse(message.utf8Data);
				}
				catch(e)
				{
					error('Invalid JSON: ' + message.utf8Data);
					return;
				}
				receive(json);
		});

	}

	/**
	 * Receive a message from the server.
	 */
	function receive(message)
	{
		if (!message || !message.type)
		{
			error('Wrong message ' + JSON.stringify(message));
			return;
		}
		if (message.type == 'start')
		{
			log.debug('Starting game for ' + self.playerId);
			setInterval(requestUpdate, Math.round(1000 / requestsPerSecond));
			return;
		}
		if (message.requestId)
		{
			latency.end(message.requestId);
		}
	}

	/**
	 * Request an update from the server.
	 */
	function requestUpdate()
	{
		if (connection.connected)
		{
			var update = {
				requestId: Math.floor(Math.random() * 0x100000000).toString(16),
				type: 'ping',
			};
			connection.sendUTF(JSON.stringify(update));
			latency.start(update.requestId);
		}
	}
}

/**
 * Run a load test.
 * Options is an object which may have:
 *	- url: mandatory URL to access.
 *	- concurrency: how many concurrent clients to use.
 *	- requestsPerSecond: how many requests per second per client.
 *	- maxRequests: how many requests to send
 *	- maxSeconds: how long to run the tests.
 *	- noAgent: if true, then do not use connection keep-alive.
 * An optional callback will be called if/when the test finishes.
 */
exports.loadTest = function(options, callback)
{
	var constructor;
	if (!options.url)
	{
		log.error('Missing URL in options');
		return;
	}
	if (options.url.startsWith('ws://'))
	{
		constructor = function(params)
		{
			return new WebsocketClient(params.url, params.requestsPerSecond);
		};
	}
	else if (options.url.startsWith('http'))
	{
		constructor = function(params)
		{
			return new HttpClient(params);
		};
	}
	else
	{
		return help();
	}
	if (callback)
	{
		options.callback = callback;
	}
	latency = new timing.Latency(options);
	startClients(options, constructor);
}

/**
 * Start a number of measuring clients.
 */
function startClients(options, constructor)
{
	var clients = {};
	var url = options.url;
	for (var index = 0; index < options.concurrency; index++)
	{
		if (options.indexParam)
		{
			options.url = url.replaceAll(indexParam, index);
		}
		clients[index] = constructor(options);
		// start each client 100 ms after the last
		setTimeout(clients[index].start, (index * 100) % 1000);
	}
	if (options.maxSeconds)
	{
		setTimeout(getClientStopper(clients), options.maxSeconds * 1000);
	}
}

/**
 * Get a function that stops all clients.
 */
var getClientStopper = function(clients)
{
	return function()
	{
		for (var index in clients)
		{
			clients[index].stop();
		}
	};
}

/**
 * Display online help.
 */
function help()
{
	console.log('Usage: loadtest [options] URL');
	console.log('  where URL can be a regular HTTP or websocket URL.');
	console.log('Options are:');
	console.log('    -n requests     Number of requests to perform');
	console.log('    -c concurrency  Number of multiple requests to make');
	console.log('    -t timelimit    Seconds to max. wait for responses');
	console.log('    --rps           Requests per second for each client');
	console.log('    --noagent       Do not use http agent (default)');
	console.log('    --agent         Use http agent (Connection: keep-alive)');
	console.log('    --index param   Replace the value of param with an index in the URL');
}

/**
 * Parse one argument and change options accordingly.
 * Returns true if there may be more arguments to parse.
 */
function parseArgument(args, options)
{
	if (args.length <= 1)
	{
		return false;
	}
	if (!args[0].startsWith('-'))
	{
		return false;
	}
	// consume the argument
	var argument = args.shift();
	switch(argument)
	{
		case '-n':
			options.maxRequests = args.shift();
			return true;
		case '-c':
			options.concurrency = args.shift();
			return true;
		case '-t':
			options.maxSeconds = args.shift();
			return true;
		case '--rps':
			options.requestsPerSecond = args.shift();
			return true;
		case '--noagent':
			return true;
		case '--agent':
			options.noAgent = false;
			return true;
	}
	console.error('Unknown option %s', argument);
	return false;
}

/**
 * Process command line arguments and run
 */
exports.run = function(args)
{
	var options = DEFAULT_OPTIONS;
	while (parseArgument(args, options))
	{
	}
	if (args.length != 1)
	{
		if (args.length == 0)
		{
			console.error('Missing URL');
		}
		else
		{
			console.error('Unknown arguments %s', JSON.stringify(args));
		}
		return help();
	}
	options.url = args[0];
	exports.loadTest(options);
}

// start load test if invoked directly
if (__filename == process.argv[1])
{
	exports.run(process.argv.slice(2));
}

<|endoftext|>


<commit_before>var app = require('express')(),
    http = require('http').Server(app)
    io = require('socket.io')(http)
    uuid = require('uuid')
    crypto = require('crypto')

    MongoClient = require('mongodb').MongoClient
    mongoDb = null
    assert = require('assert')

var config = {
  port: process.env.PORT || 3001,
  mongoUrl: process.env.MONGO_URL || 'mongodb://localhost:27017/aciojs'
}

MongoClient.connect(config.mongoUrl, (err, db) => {
  assert.equal(null, err)
  mongoDb = db

  if (process.env.NODE_ENV === 'development') {
    mongoDb.collection('Clients').drop()
    mongoDb.collection('JobsResults').drop()
  }

  http.listen(config.port, () => {
    console.log('listening on *:' + config.port)
  })
})

emitJob = (socket) => {
  mongoDb.collection('Jobs').findOne({
    status: 'working'
  }, {
    jobId:1, code:1, type:1
  }, (err, result) => {
    if (!err && result) {
      socket.emit('work', result)
    }
  })
}

io.on('connection', (socket) => {

  var _id = socket.id.replace('/#', '')

  mongoDb.collection('Clients').insert({
    _id: _id,
    handshake: socket.handshake
  })

  socket.on('disconnect', () => {
    mongoDb.collection('Clients').remove({
      _id: _id
    })
  })

  socket.on('result', (result) => {
    result.socket = _id
    result.resultId = uuid.v4()
    result.createdAt = new Date()
    result.hashedResult = crypto.createHash('md5').update(JSON.stringify(result.data)).digest('hex')

    mongoDb.collection('JobsResults').insert(result, (err, res) => {
      if (!err && res) {
        if (err) { return false }
        if (!!result.reqNewJob) {
          emitJob(socket)
        }
      }
    })

  })

  socket.on('status', (status) => {

    if (status === 'working') {

    } else if (status === 'ready') {
      emitJob(socket)
    }

  })

})
<commit_msg>Add reqNewJob parameter<commit_after>var app = require('express')(),
    http = require('http').Server(app)
    io = require('socket.io')(http)
    uuid = require('uuid')
    crypto = require('crypto')

    MongoClient = require('mongodb').MongoClient
    mongoDb = null
    assert = require('assert')

var config = {
  port: process.env.PORT || 3001,
  mongoUrl: process.env.MONGO_URL || 'mongodb://localhost:27017/aciojs'
}

MongoClient.connect(config.mongoUrl, (err, db) => {
  assert.equal(null, err)
  mongoDb = db

  if (process.env.NODE_ENV === 'development') {
    mongoDb.collection('Clients').drop()
    mongoDb.collection('JobsResults').drop()
  }

  http.listen(config.port, () => {
    console.log('listening on *:' + config.port)
  })
})

emitJob = (socket) => {
  mongoDb.collection('Jobs').findOne({
    status: 'working'
  }, {
    jobId:1, code:1, type:1
  }, (err, result) => {
    if (!err && result) {
      socket.emit('work', result)
    }
  })
}

io.on('connection', (socket) => {

  var _id = socket.id.replace('/#', '')

  mongoDb.collection('Clients').insert({
    _id: _id,
    handshake: socket.handshake
  })

  socket.on('disconnect', () => {
    mongoDb.collection('Clients').remove({
      _id: _id
    })
  })

  socket.on('result', (result) => {

    result.socket = _id
    result.resultId = uuid.v4()
    result.createdAt = new Date()
    result.hashedResult = crypto.createHash('md5').update(JSON.stringify(result.data)).digest('hex')

    mongoDb.collection('JobsResults').insert(result, (err, result) => {
      if (!err && result) {
        if (err) { return false }
        emitJob(socket)
      }
    })

  })

  socket.on('status', (status) => {

    if (status === 'working') {

    } else if (status === 'ready') {
      emitJob(socket)
    }

  })

})
<|endoftext|>


<commit_before>var fs            = require('fs');
var moment        = require('moment');
var config        = require('./../config');
var client        = require('./elasticSearch');
var splunkService = require('./splunk');
var RedisSplunk   = require('./redisSplunk');

var events = require('./database').events;

module.exports = function(eventCode, data) {

  // add timestamp if one isn't passed
  if (data && !data.hasOwnProperty("timestamp")){
    var newTimestamp = new Date().getTime();
    data.timestamp = newTimestamp;
  }
  // moment().toISOString()
  data.timestamp = moment(data.timestamp).toISOString()

  if(eventCode === undefined){
    eventCode = 0;
  }
  data.eventCode = eventCode;
  var uuid = eventCode; //Set the Default to EventCode just in case.
  if (data && data.hasOwnProperty("uuid")){ // if the data has a uuid (and it always should)
        uuid = data.uuid; // set the uuid to the actual uuid.
  }

  if(config.log){
    fs.appendFile('./skynet.txt', JSON.stringify(data) + '\r\n', function (err) {
      if (err) {
        throw err;
      }
    });

    if(config.elasticSearch && config.elasticSearch.hosts){
      if(data._id){
        try{
          data._id.toString();
          delete data._id;
        } catch(e){
          console.log(e);
        }
      }

      client.index({
        // index: "log",
        // type: eventCode,
        index: "skynet_trans_log",
        type: uuid,
        timestamp: data.timestamp,
        body: data
      }, function (error, response) {
        if(error){
          console.log(error);
        }
      });
    }

    RedisSplunk.log(data, function(err){
      if(err){
        console.error(err);
      }
    });
  }

  events.insert(data, function(err, saved) {
    if(err || saved.length < 1) {
      console.log('Error logging event: ' + JSON.stringify(data));
      console.log('Error: ' + err);
    }
  });
};
<commit_msg>show erroring message<commit_after>var fs            = require('fs');
var moment        = require('moment');
var config        = require('./../config');
var client        = require('./elasticSearch');
var splunkService = require('./splunk');
var RedisSplunk   = require('./redisSplunk');

var events = require('./database').events;

module.exports = function(eventCode, data) {

  // add timestamp if one isn't passed
  if (data && !data.hasOwnProperty("timestamp")){
    var newTimestamp = new Date().getTime();
    data.timestamp = newTimestamp;
  }
  // moment().toISOString()
  data.timestamp = moment(data.timestamp).toISOString()

  if(eventCode === undefined){
    eventCode = 0;
  }
  data.eventCode = eventCode;
  var uuid = eventCode; //Set the Default to EventCode just in case.
  if (data && data.hasOwnProperty("uuid")){ // if the data has a uuid (and it always should)
        uuid = data.uuid; // set the uuid to the actual uuid.
  }

  if(config.log){
    fs.appendFile('./skynet.txt', JSON.stringify(data) + '\r\n', function (err) {
      if (err) {
        throw err;
      }
    });

    if(config.elasticSearch && config.elasticSearch.hosts){
      if(data._id){
        try{
          data._id.toString();
          delete data._id;
        } catch(e){
          console.log(e);
        }
      }

      var msg = {
        index: "skynet_trans_log",
        type: uuid,
        timestamp: data.timestamp,
        body: data
      };
      client.index(msg, function (error, response) {
        if(error){
          console.log(error, msg);
        }
      });
    }

    RedisSplunk.log(data, function(err){
      if(err){
        console.error(err);
      }
    });
  }

  events.insert(data, function(err, saved) {
    if(err || saved.length < 1) {
      console.log('Error logging event: ' + JSON.stringify(data));
      console.log('Error: ' + err);
    }
  });
};
<|endoftext|>


<commit_before>// Every start, if it started from nodemon,
// should increase server API major version number,
// to force client reload.
// When deployed in production,
// The version number should come from git commit.
// Server version used to make sure that
// if server was rebooted, or client disconnected,
// they will communicate consistently.

const PORT = process.env.PORT || 8080;

const Promise = require('bluebird');
// const CircularJSON = require('circular-json');

// Compiling browser-side assets
// 1. Normalize existing css. Replace surrounding single quotes
//    with double quotes.
// var

var cssMinifer = require('./lib/css-minifier');

var assetsCompiler = require('./lib/assets-compiler');

let lastClientCodeHash = null;
let indexJsFile = null;
let indexJsMapFile = null;

let afterFirstCompileCallback = null;

assetsCompiler.onComplete((jsBundleFile, mapFile, hash, stats) => {

  var firstNotify = (!lastClientCodeHash && afterFirstCompileCallback);

  lastClientCodeHash = hash;

  // Replace hash in bundled file:
  // Search for assignment window.JAVASCRIPT_BUNDLE_HASH = 'REPLACE_WEBPACK_HASH';

  var hashPos = jsBundleFile.indexOf('REPLACE_WEBPACK_HASH');
  if (hashPos === -1) {
    console.log(new Date().valueOf(),
      `Browser-side assets reported that bundled successfully but found no hash. Skipping.
       Add window.JAVASCRIPT_BUNDLE_HASH = 'REPLACE_WEBPACK_HASH' at the most beginning of main entry`,
      hash);
    console.log(jsBundleFile.size);
    return;
  }
  jsBundleFile.write(hash, hashPos, 20);

  indexJsFile = jsBundleFile;
  indexJsMapFile = mapFile;

  // console.log(JSON.parse(indexJsMapFile));

  console.log(new Date().valueOf(),
    'Browser-side assets bundled successfully.',
    hash);

  if (firstNotify) {
    afterFirstCompileCallback();
  }

  try {
    wss.sendAll(JSON.stringify({ debug: { reload: true, hash } }));
    // wss.sendAll(JSON.stringify(
    //   { debug: { file: jsBundleFile.toString('base64'), hash } }));
  } catch (e) {
  }

});

assetsCompiler.onError(errors => {
  console.error('Webpack Bundling errors:', errors);
  errors = errors.map(error => error.message);
  try {
    wss.sendAll(JSON.stringify({ debug: { errors } }));
  } catch (e) {
    console.log(e);
  }
});

// SQL queries

// Format: postgres://user:password@server:5432/database
const DATABASE_URL = process.env.DATABASE_URL;

const pgp = require('pg-promise')({ promiseLib: Promise });
const sql = pgp(DATABASE_URL);

// Database Migrations
const dbMigrate = require('./lib/db-migrate')(DATABASE_URL);

// Hashing passwords
const pwdHash = require('./lib/pwd-hash');

// HTTP Server

const hostedFiles = {
  // file path,
  // type, cache time, cache tag
  '/': [ 'index.html',
    'text/html', 0, null ],

  '/index.js': [ function () { return indexJsFile; },
    'application/javascript; charset=UTF-8', 3, null ],

  '/index.js.map': [ function () { return indexJsMapFile; },
    'application/json; charset=UTF-8', 3, null ],

  '/layout_grid.gif': [ '/layout_grid.gif',
    'image/gif', 3, null ],

  '/index.css': [ '/index.css',
    'text/css; charset=UTF-8', 3, null ],
};

const hostAFile = require('./lib/host-a-file')(hostedFiles);

const server = require('http')
  .createServer(
    (req, res) => {
      if (hostedFiles[req.url]) {
        return hostAFile(req, res);
      } else {
        // TODO: check browser-side route and return index.html
      }

      sql.one(`SELECT 1`)
        .then(one => {
          res.end(`Hello from Heroku!<br/>SQL SELECT 1 returned ${ one }`);
        });
    }
  )
  .listen(PORT,
    err => {
      if (err) {
        return console.log(`Port ${ PORT } is occupied`, err);
      }

      console.log(`Listening on port ${ PORT }`);
    }
  );

const uuid = require('uuid/v4');
const serverRunId = uuid();

const WebSocket = require('ws');

const wss = new WebSocket.Server({ server });
const clientAddress = require('./lib/client-address');

// Implement sessions to send "bundle recompiled"
// to all debugged clients.
// Implement custom url debug mode enablers
// or another way to activate debug mode
// to support even first errors logging.

wss.sendAll = function sendAll (data) {
  this.clients.forEach(function (client) {
    try {
      client.send(data);
    } catch (e) {
    }
  });
};

function sendAfterCompileFinished (ws, addr) {
  if (lastClientCodeHash) {
    try {
      ws.send(JSON.stringify({
        client: addr,
        srvRunId: serverRunId,
        cltCodeHash: lastClientCodeHash
      }));
    } catch (e) {
      return;
    }
  } else {
    afterFirstCompileCallback = function () {
      sendAfterCompileFinished(ws, addr);
    };
  }
}

wss.on('connection', (ws, req) => {

  const addr = clientAddress(req);
  console.log(
    new Date().valueOf(),
    addr.ip + ':' + addr.port,
    'A WebSocket client connected');

  sendAfterCompileFinished(ws);

  ws.on('message', message => {
    let data = null;
    try {
      if (message.length) {
        data = JSON.parse(message);
      } else {
        data = '';
      }
    } catch (e) {
      console.log(e);
      return;
    }
    if (typeof data === 'string' &&
      data.length === 0) {

      // Keepalive packet
      /* console.log(
        new Date().valueOf(),
        addr.ip + ':' + addr.port,
        'HEARTBEAT'); */

      ws.send('');
    } else if (data) {

      if (data.debug) {
        if (data.debug.message &&
            data.debug.message[4] &&
            typeof(data.debug.message[4]) == 'object' &&
            data.debug.message[4].line &&
            data.debug.message[4].column) {

          var SourceMapConsumer = require('source-map')
            .SourceMapConsumer;
          var smc = new SourceMapConsumer(
            JSON.parse(indexJsMapFile));

          // { source: 'http://example.com/www/js/two.js',
          //   line: 2,
          //   column: 10,
          //   name: 'n' }
          var pos = smc.originalPositionFor({
            line: data.debug.message[4].line,
            column: data.debug.message[4].column
          });

          console.log(data.debug.time,
            addr.ip + ':' + addr.port,
            data.debug.message[0],
            '"' + pos.name + '" at line ' + pos.line +
            ' col ' + pos.column + ' in ' +
            pos.source);

        } else {
          const args =
            [// data.debug.time,
             // addr.ip + ':' + addr.port
            ]
            .concat(data.debug.message);

          console.log.apply(console, args);
        }
      }
    }
  });
});

<commit_msg>Logging of the file size when Webpack produces buggy result<commit_after>// Every start, if it started from nodemon,
// should increase server API major version number,
// to force client reload.
// When deployed in production,
// The version number should come from git commit.
// Server version used to make sure that
// if server was rebooted, or client disconnected,
// they will communicate consistently.

const PORT = process.env.PORT || 8080;

const Promise = require('bluebird');
// const CircularJSON = require('circular-json');

// Compiling browser-side assets
// 1. Normalize existing css. Replace surrounding single quotes
//    with double quotes.
// var

var cssMinifer = require('./lib/css-minifier');

var assetsCompiler = require('./lib/assets-compiler');

let lastClientCodeHash = null;
let indexJsFile = null;
let indexJsMapFile = null;

let afterFirstCompileCallback = null;

assetsCompiler.onComplete((jsBundleFile, mapFile, hash, stats) => {

  var firstNotify = (!lastClientCodeHash && afterFirstCompileCallback);

  lastClientCodeHash = hash;

  // Replace hash in bundled file:
  // Search for assignment window.JAVASCRIPT_BUNDLE_HASH = 'REPLACE_WEBPACK_HASH';

  var hashPos = jsBundleFile.indexOf('REPLACE_WEBPACK_HASH');
  if (hashPos === -1) {
    console.log(new Date().valueOf(),
      `Browser-side assets reported that bundled successfully but found no hash. Skipping.
       Add window.JAVASCRIPT_BUNDLE_HASH = 'REPLACE_WEBPACK_HASH' at the most beginning of main entry`,
      hash);
    console.log(jsBundleFile.length);
    return;
  }
  jsBundleFile.write(hash, hashPos, 20);

  indexJsFile = jsBundleFile;
  indexJsMapFile = mapFile;

  // console.log(JSON.parse(indexJsMapFile));

  console.log(new Date().valueOf(),
    'Browser-side assets bundled successfully.',
    hash);

  if (firstNotify) {
    afterFirstCompileCallback();
  }

  try {
    wss.sendAll(JSON.stringify({ debug: { reload: true, hash } }));
    // wss.sendAll(JSON.stringify(
    //   { debug: { file: jsBundleFile.toString('base64'), hash } }));
  } catch (e) {
  }

});

assetsCompiler.onError(errors => {
  console.error('Webpack Bundling errors:', errors);
  errors = errors.map(error => error.message);
  try {
    wss.sendAll(JSON.stringify({ debug: { errors } }));
  } catch (e) {
    console.log(e);
  }
});

// SQL queries

// Format: postgres://user:password@server:5432/database
const DATABASE_URL = process.env.DATABASE_URL;

const pgp = require('pg-promise')({ promiseLib: Promise });
const sql = pgp(DATABASE_URL);

// Database Migrations
const dbMigrate = require('./lib/db-migrate')(DATABASE_URL);

// Hashing passwords
const pwdHash = require('./lib/pwd-hash');

// HTTP Server

const hostedFiles = {
  // file path,
  // type, cache time, cache tag
  '/': [ 'index.html',
    'text/html', 0, null ],

  '/index.js': [ function () { return indexJsFile; },
    'application/javascript; charset=UTF-8', 3, null ],

  '/index.js.map': [ function () { return indexJsMapFile; },
    'application/json; charset=UTF-8', 3, null ],

  '/layout_grid.gif': [ '/layout_grid.gif',
    'image/gif', 3, null ],

  '/index.css': [ '/index.css',
    'text/css; charset=UTF-8', 3, null ],
};

const hostAFile = require('./lib/host-a-file')(hostedFiles);

const server = require('http')
  .createServer(
    (req, res) => {
      if (hostedFiles[req.url]) {
        return hostAFile(req, res);
      } else {
        // TODO: check browser-side route and return index.html
      }

      sql.one(`SELECT 1`)
        .then(one => {
          res.end(`Hello from Heroku!<br/>SQL SELECT 1 returned ${ one }`);
        });
    }
  )
  .listen(PORT,
    err => {
      if (err) {
        return console.log(`Port ${ PORT } is occupied`, err);
      }

      console.log(`Listening on port ${ PORT }`);
    }
  );

const uuid = require('uuid/v4');
const serverRunId = uuid();

const WebSocket = require('ws');

const wss = new WebSocket.Server({ server });
const clientAddress = require('./lib/client-address');

// Implement sessions to send "bundle recompiled"
// to all debugged clients.
// Implement custom url debug mode enablers
// or another way to activate debug mode
// to support even first errors logging.

wss.sendAll = function sendAll (data) {
  this.clients.forEach(function (client) {
    try {
      client.send(data);
    } catch (e) {
    }
  });
};

function sendAfterCompileFinished (ws, addr) {
  if (lastClientCodeHash) {
    try {
      ws.send(JSON.stringify({
        client: addr,
        srvRunId: serverRunId,
        cltCodeHash: lastClientCodeHash
      }));
    } catch (e) {
      return;
    }
  } else {
    afterFirstCompileCallback = function () {
      sendAfterCompileFinished(ws, addr);
    };
  }
}

wss.on('connection', (ws, req) => {

  const addr = clientAddress(req);
  console.log(
    new Date().valueOf(),
    addr.ip + ':' + addr.port,
    'A WebSocket client connected');

  sendAfterCompileFinished(ws);

  ws.on('message', message => {
    let data = null;
    try {
      if (message.length) {
        data = JSON.parse(message);
      } else {
        data = '';
      }
    } catch (e) {
      console.log(e);
      return;
    }
    if (typeof data === 'string' &&
      data.length === 0) {

      // Keepalive packet
      /* console.log(
        new Date().valueOf(),
        addr.ip + ':' + addr.port,
        'HEARTBEAT'); */

      ws.send('');
    } else if (data) {

      if (data.debug) {
        if (data.debug.message &&
            data.debug.message[4] &&
            typeof(data.debug.message[4]) == 'object' &&
            data.debug.message[4].line &&
            data.debug.message[4].column) {

          var SourceMapConsumer = require('source-map')
            .SourceMapConsumer;
          var smc = new SourceMapConsumer(
            JSON.parse(indexJsMapFile));

          // { source: 'http://example.com/www/js/two.js',
          //   line: 2,
          //   column: 10,
          //   name: 'n' }
          var pos = smc.originalPositionFor({
            line: data.debug.message[4].line,
            column: data.debug.message[4].column
          });

          console.log(data.debug.time,
            addr.ip + ':' + addr.port,
            data.debug.message[0],
            '"' + pos.name + '" at line ' + pos.line +
            ' col ' + pos.column + ' in ' +
            pos.source);

        } else {
          const args =
            [// data.debug.time,
             // addr.ip + ':' + addr.port
            ]
            .concat(data.debug.message);

          console.log.apply(console, args);
        }
      }
    }
  });
});

<|endoftext|>


<commit_before>// Copyright (c) 2017 The Regents of the University of Michigan.
// All Rights Reserved. Licensed according to the terms of the Revised
// BSD License. See LICENSE.txt for details.

var factory = function(object) {
  var c;
  var denominator = 1;
  var numerator = 0;
  var children = [ ];
  var is_complete = false;

  var log_tree = { };

  if (object.hasOwnProperty("c")) {
    for (c of object.c) {
      children.push(factory(c));
    }
  }

  for (c of children) {
    denominator += c.den();
  }

  log_tree.description = "";
  log_tree.num = function() {
    var result = is_complete ? 1 : 0;
    for (let x of children) {
      result += x.num();
    }

    return result;
  };
  log_tree.den = function() { return denominator; };

  log_tree.complete = function(json_string) {
    var array, timestamp, code, message;
    array = JSON.parse(json_string);
    timestamp = array.shift();
    code = array.shift();
    message = array.pop();
    log_tree.mark_true(array);
  };

  log_tree.mark_true = function(array) {
    var i;

    if (array.length == 0) {
      is_complete = true;
    } else {
      i = array.shift();
      children[i].mark_true(array);
    }
  };

  log_tree[Symbol.iterator] = function() {
    return children[Symbol.iterator]();
  };

  return log_tree;
};

module.exports = factory;
<commit_msg>:muscle: Use "let" instead of "var" for iteration<commit_after>// Copyright (c) 2017 The Regents of the University of Michigan.
// All Rights Reserved. Licensed according to the terms of the Revised
// BSD License. See LICENSE.txt for details.

var factory = function(object) {
  var denominator = 1;
  var numerator = 0;
  var children = [ ];
  var is_complete = false;

  var log_tree = { };

  if (object.hasOwnProperty("c")) {
    for (let c of object.c) {
      children.push(factory(c));
    }
  }

  for (let c of children) {
    denominator += c.den();
  }

  log_tree.description = "";
  log_tree.num = function() {
    var result = is_complete ? 1 : 0;
    for (let x of children) {
      result += x.num();
    }

    return result;
  };
  log_tree.den = function() { return denominator; };

  log_tree.complete = function(json_string) {
    var array, timestamp, code, message;
    array = JSON.parse(json_string);
    timestamp = array.shift();
    code = array.shift();
    message = array.pop();
    log_tree.mark_true(array);
  };

  log_tree.mark_true = function(array) {
    var i;

    if (array.length == 0) {
      is_complete = true;
    } else {
      i = array.shift();
      children[i].mark_true(array);
    }
  };

  log_tree[Symbol.iterator] = function() {
    return children[Symbol.iterator]();
  };

  return log_tree;
};

module.exports = factory;
<|endoftext|>


<commit_before>'use strict';

var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io').listen(server);
var device  = require('express-device');
var runningPortNumber = 80; //process.env.PORT || 80;
var securityCode = process.argv[2];

if (!securityCode) {
    console.error('run with security code!!');
    process.exit(-1);
} else {
    securityCode = securityCode.trim();
}

var polls = require(__dirname + '/data/polls.js');

var defaultPoll = polls(0);
defaultPoll.open();

var currentPoll = defaultPoll;

function setNewPoll(newPoll) {
    if (!newPoll) {
        return;
    }

    if (currentPoll && !currentPoll.revotable) {
        currentPoll.close();
    }

    currentPoll = newPoll;
    currentPoll.open();
    return true;
}

app.configure(function () {
    app.use(express.static(__dirname + '/public'));

    app.set('view engine', 'ejs');
    app.set('views', __dirname + '/views');

    app.use(device.capture());
});

app.use(function (req, res, next) {
    // output every request in the array
    console.log({
        method: req.method,
        url: req.url,
        device: req.device
    });

    // goes onto the next function in line
    next();
});

function validateRequest(req) {
    if (!req) { return false; }
    if (!req.query) { return false; }
    if (req.query.auth !== securityCode) { return false; }

    return true;
}

app.get('/poll/open/:id', function (req, res) {
    var success = validateRequest(req);

    if (success) {
        success = setNewPoll(polls(req.params.id));
    }

    if (success) {
        io.sockets.clients().forEach(function (socket) {
            var ip = socket.handshake.address.address;
            socket.emit('newPoll', currentPoll.toVoter(ip));
        });

        io.sockets.emit('pollStats', currentPoll.countVotes());
    }

    res.json({
        success: !!success
    });
});

app.get('/poll/close', function (req, res) {
    var success = validateRequest(req);

    if (success) {
        success = setNewPoll(defaultPoll);
    }

    if (success) {
        io.sockets.clients().forEach(function (socket) {
            var ip = socket.handshake.address.address;
            socket.emit('newPoll', currentPoll.toVoter(ip));
        });

        io.sockets.emit('pollStats', currentPoll.countVotes());
    }

    res.json({
        success: !!success
    });
});

io.sockets.on('connection', function (socket) {
    var ip = socket.handshake.address.address;
    var poll = currentPoll && currentPoll.canVote(ip) ? currentPoll : defaultPoll;

    socket.emit('newPoll', poll.toVoter(ip));
    socket.emit('pollStats', poll.countVotes());

    socket.on('vote', function (data) {
        var pollId = +data.pollId,
            poll = polls(pollId),
            key = data.key;

        if (poll.vote(pollId, ip, key)) {
            if (poll === currentPoll) {
                io.sockets.emit('pollStats', currentPoll.countVotes());
            }
        } else {
            console.log('reject vote');
        }

        if (!poll.canVote(ip)) {
            socket.emit('newPoll', defaultPoll.toVoter(ip));
        }
    });
});

server.listen(runningPortNumber, '0.0.0.0');
<commit_msg>bugfix<commit_after>'use strict';

var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io').listen(server);
var device  = require('express-device');
var runningPortNumber = 80; //process.env.PORT || 80;
var securityCode = process.argv[2];

if (!securityCode) {
    console.error('run with security code!!');
    process.exit(-1);
} else {
    securityCode = securityCode.trim();
}

var polls = require(__dirname + '/data/polls.js');

var defaultPoll = polls(0);
defaultPoll.open();

var currentPoll = defaultPoll;

function setNewPoll(newPoll) {
    if (!newPoll) {
        return;
    }

    if (currentPoll && !currentPoll.revotable) {
        currentPoll.close();
    }

    currentPoll = newPoll;
    currentPoll.open();
    return true;
}

app.configure(function () {
    app.use(express.static(__dirname + '/public'));

    app.set('view engine', 'ejs');
    app.set('views', __dirname + '/views');

    app.use(device.capture());
});

app.use(function (req, res, next) {
    // output every request in the array
    console.log({
        method: req.method,
        url: req.url,
        device: req.device
    });

    // goes onto the next function in line
    next();
});

function validateRequest(req) {
    if (!req) { return false; }
    if (!req.query) { return false; }
    if (req.query.auth !== securityCode) { return false; }

    return true;
}

app.get('/poll/open/:id', function (req, res) {
    var success = validateRequest(req);

    if (success) {
        success = setNewPoll(polls(req.params.id));
    }

    if (success) {
        io.sockets.clients().forEach(function (socket) {
            var ip = socket.handshake.address.address;
            var poll = currentPoll.canVote(ip) ? currentPoll : defaultPoll;
            socket.emit('newPoll', poll.toVoter(ip));
        });

        io.sockets.emit('pollStats', currentPoll.countVotes());
    }

    res.json({
        success: !!success
    });
});

app.get('/poll/close', function (req, res) {
    var success = validateRequest(req);

    if (success) {
        success = setNewPoll(defaultPoll);
    }

    if (success) {
        io.sockets.clients().forEach(function (socket) {
            var ip = socket.handshake.address.address;
            var poll = currentPoll.canVote(ip) ? currentPoll : defaultPoll;
            socket.emit('newPoll', poll.toVoter(ip));
        });

        io.sockets.emit('pollStats', currentPoll.countVotes());
    }

    res.json({
        success: !!success
    });
});

io.sockets.on('connection', function (socket) {
    var ip = socket.handshake.address.address;
    var poll = currentPoll && currentPoll.canVote(ip) ? currentPoll : defaultPoll;

    socket.emit('newPoll', poll.toVoter(ip));
    socket.emit('pollStats', poll.countVotes());

    socket.on('vote', function (data) {
        var pollId = +data.pollId,
            poll = polls(pollId),
            key = data.key;

        if (poll.vote(pollId, ip, key)) {
            if (poll === currentPoll) {
                io.sockets.emit('pollStats', currentPoll.countVotes());
            }
        } else {
            console.log('reject vote');
        }

        if (!poll.canVote(ip)) {
            socket.emit('newPoll', defaultPoll.toVoter(ip));
        }
    });
});

server.listen(runningPortNumber, '0.0.0.0');
<|endoftext|>


<commit_before>'use strict';
const http = require('http');
const StaticServer = require('node-static').Server;
const io = require('socket.io');
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
const async = require('async');
const SonosDiscovery = require('sonos-discovery');
const settings = {
  port: 8080,
  cacheDir: './cache'
}

try {
  const userSettings = require(path.resolve(__dirname, 'settings.json'));
  for (var i in userSettings) {
    settings[i] = userSettings[i];
  }
} catch (e) {
  console.log('no settings file found, will only use default settings');
}

var discovery = new SonosDiscovery(settings);

var cacheDir = path.resolve(__dirname, settings.cacheDir);
var missingAlbumArt = path.resolve(__dirname, './lib/browse_missing_album_art.png');

var fileServer = new StaticServer(path.resolve(__dirname, 'static'));

var queues = {};

fs.mkdir(cacheDir, function (e) {
  if (e && e.code != 'EEXIST')
    console.log('creating cache dir failed!', e);
});

var server = http.createServer(function (req, res) {
  if (/^\/getaa/.test(req.url)) {
    // this is a resource, download from player and put in cache folder
    var md5url = crypto.createHash('md5').update(req.url).digest('hex');
    var fileName = path.join(cacheDir, md5url);

    fs.exists(fileName, function (exists) {
      if (exists) {
        var readCache = fs.createReadStream(fileName);
        readCache.pipe(res);
        return;
      }

      const player = discovery.getAnyPlayer();
      if (!player) return;

      console.log('fetching album art from', player.localEndpoint);
      http.get(`${player.baseUrl}${req.url}`, function (res2) {
        console.log(res2.statusCode);
        if (res2.statusCode == 200) {
          if (!fs.exists(fileName)) {
            var cacheStream = fs.createWriteStream(fileName);
            res2.pipe(cacheStream);
          } else {
            res2.resume();
          }
        } else if (res2.statusCode == 404) {
          // no image exists! link it to the default image.
          console.log(res2.statusCode, 'linking', fileName)
          fs.link(missingAlbumArt, fileName, function (e) {
            res2.resume();
            if (e) console.log(e);
          });
        }

        res2.on('end', function () {
          console.log('serving', req.url);
          var readCache = fs.createReadStream(fileName);
          readCache.on('error', function (e) {
            console.log(e);
          });
          readCache.pipe(res);
        });
      }).on('error', function (e) {
        console.log("Got error: " + e.message);
      });
    });
  } else {
    req.addListener('end', function () {
      fileServer.serve(req, res);
    }).resume();
  }
});

var socketServer = io.listen(server);

socketServer.sockets.on('connection', function (socket) {
  // Send it in a better format
  const players = discovery.players;

  if (players.length == 0) return;

  socket.emit('topology-change', players);
  discovery.getFavorites()
    .then((favorites) => {
      socket.emit('favorites', favorites);
    });

  socket.on('transport-state', function (data) {
    // find player based on uuid
    const player = discovery.getPlayerByUUID(data.uuid);

    if (!player) return;

    // invoke action
    //console.log(data)
    player[data.state]();
  });

  socket.on('group-volume', function (data) {
    // find player based on uuid
    const player = discovery.getPlayerByUUID(data.uuid);
    if (!player) return;

    // invoke action
    player.setGroupVolume(data.volume);
  });

  socket.on('group-management', function (data) {
    // find player based on uuid
    console.log(data)
    const player = discovery.getPlayerByUUID(data.player);
    if (!player) return;

    if (data.group == null) {
      player.becomeCoordinatorOfStandaloneGroup();
      return;
    }

    player.setAVTransport(`x-rincon:${data.group}`);
  });

  socket.on('play-favorite', function (data) {
    var player = discovery.getPlayerByUUID(data.uuid);
    if (!player) return;

    player.replaceWithFavorite(data.favorite)
      .then(() => player.play());
  });

  socket.on('queue', function (data) {
    loadQueue(data.uuid)
      .then(queue => {
        socket.emit('queue', { uuid: data.uuid, queue });
      });
  });

  socket.on('seek', function (data) {
    var player = discovery.getPlayerByUUID(data.uuid);
    if (player.avTransportUri.startsWith('x-rincon-queue')) {
      player.trackSeek(data.trackNo);
      return;
    }

    // Player is not using queue, so start queue first
    player.setAVTransport('x-rincon-queue:' + player.uuid + '#0')
      .then(() => player.trackSeek(data.trackNo))
      .then(() => player.play());
  });

  socket.on('playmode', function (data) {
    var player = discovery.getPlayerByUUID(data.uuid);
    for (var action in data.state) {
      player[action](data.state[action]);
    }
  });

  socket.on('volume', function (data) {
    var player = discovery.getPlayerByUUID(data.uuid);
    player.setVolume(data.volume);
  });

  socket.on('group-mute', function (data) {
    console.log(data)
    var player = discovery.getPlayerByUUID(data.uuid);
    if (data.mute)
      player.muteGroup();
    else
      player.unMuteGroup();
  });

  socket.on('mute', function (data) {
    var player = discovery.getPlayerByUUID(data.uuid);
    if (data.mute)
      player.mute();
    else
      player.unMute();
  });

  socket.on('track-seek', function (data) {
    var player = discovery.getPlayerByUUID(data.uuid);
    player.timeSeek(data.elapsed);
  });

  socket.on('search', function (data) {
    search(data.term, socket);
  });

  socket.on("error", function (e) {
    console.error(e);
  })
});

discovery.on('topology-change', function (data) {
  socketServer.sockets.emit('topology-change', discovery.players);
});

discovery.on('transport-state', function (data) {
  socketServer.sockets.emit('transport-state', data);
});

discovery.on('group-volume', function (data) {
  socketServer.sockets.emit('group-volume', data);
});

discovery.on('volume-change', function (data) {
  socketServer.sockets.emit('volume', data);
});

discovery.on('group-mute', function (data) {
  socketServer.sockets.emit('group-mute', data);
});

discovery.on('mute-change', function (data) {
  socketServer.sockets.emit('mute', data);
});

discovery.on('favorites', function (data) {
  socketServer.sockets.emit('favorites', data);
});

discovery.on('queue-changed', function (data) {
  console.log('queue-changed', data);
  delete queues[data.uuid];
  loadQueue(data.uuid)
    .then(queue => {
      socket.emit('queue', { uuid: data.uuid, queue });
    });
});

function loadQueue(uuid) {
  if (queues[uuid]) {
    return Promise.resolve(queues[uuid]);
  }

  const player = discovery.getPlayerByUUID(uuid);
  return player.getQueue()
    .then(queue => {
      queues[uuid] = queue;
      return queue;
    });
}

function search(term, socket) {
  console.log('search for', term)
  var playerCycle = 0;
  var players = [];

  for (var i in discovery.players) {
    players.push(discovery.players[i]);
  }

  function getPlayer() {
    var player = players[playerCycle++ % players.length];
    return player;
  }

  var response = {};

  async.parallelLimit([
    function (callback) {
      var player = getPlayer();
      console.log('fetching from', player.address)
      player.browse('A:ARTIST:' + term, 0, 600, function (success, result) {
        console.log(success, result)
        response.byArtist = result;
        callback(null, 'artist');
      });
    },
    function (callback) {
      var player = getPlayer();
      console.log('fetching from', player.address)
      player.browse('A:TRACKS:' + term, 0, 600, function (success, result) {
        response.byTrack = result;
        callback(null, 'track');
      });
    },
    function (callback) {
      var player = getPlayer();
      console.log('fetching from', player.address)
      player.browse('A:ALBUM:' + term, 0, 600, function (success, result) {
        response.byAlbum = result;
        callback(null, 'album');
      });
    }
  ], players.length, function (err, result) {

    socket.emit('search-result', response);
  });
}

// Attach handler for socket.io

server.listen(settings.port);

console.log("http server listening on port", settings.port);
<commit_msg>äUpdate queue when changed<commit_after>'use strict';
const http = require('http');
const StaticServer = require('node-static').Server;
const io = require('socket.io');
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
const async = require('async');
const SonosDiscovery = require('sonos-discovery');
const settings = {
  port: 8080,
  cacheDir: './cache'
}

try {
  const userSettings = require(path.resolve(__dirname, 'settings.json'));
  for (var i in userSettings) {
    settings[i] = userSettings[i];
  }
} catch (e) {
  console.log('no settings file found, will only use default settings');
}

var discovery = new SonosDiscovery(settings);

var cacheDir = path.resolve(__dirname, settings.cacheDir);
var missingAlbumArt = path.resolve(__dirname, './lib/browse_missing_album_art.png');

var fileServer = new StaticServer(path.resolve(__dirname, 'static'));

var queues = {};

fs.mkdir(cacheDir, function (e) {
  if (e && e.code != 'EEXIST')
    console.log('creating cache dir failed!', e);
});

var server = http.createServer(function (req, res) {
  if (/^\/getaa/.test(req.url)) {
    // this is a resource, download from player and put in cache folder
    var md5url = crypto.createHash('md5').update(req.url).digest('hex');
    var fileName = path.join(cacheDir, md5url);

    fs.exists(fileName, function (exists) {
      if (exists) {
        var readCache = fs.createReadStream(fileName);
        readCache.pipe(res);
        return;
      }

      const player = discovery.getAnyPlayer();
      if (!player) return;

      console.log('fetching album art from', player.localEndpoint);
      http.get(`${player.baseUrl}${req.url}`, function (res2) {
        console.log(res2.statusCode);
        if (res2.statusCode == 200) {
          if (!fs.exists(fileName)) {
            var cacheStream = fs.createWriteStream(fileName);
            res2.pipe(cacheStream);
          } else {
            res2.resume();
          }
        } else if (res2.statusCode == 404) {
          // no image exists! link it to the default image.
          console.log(res2.statusCode, 'linking', fileName)
          fs.link(missingAlbumArt, fileName, function (e) {
            res2.resume();
            if (e) console.log(e);
          });
        }

        res2.on('end', function () {
          console.log('serving', req.url);
          var readCache = fs.createReadStream(fileName);
          readCache.on('error', function (e) {
            console.log(e);
          });
          readCache.pipe(res);
        });
      }).on('error', function (e) {
        console.log("Got error: " + e.message);
      });
    });
  } else {
    req.addListener('end', function () {
      fileServer.serve(req, res);
    }).resume();
  }
});

var socketServer = io.listen(server);

socketServer.sockets.on('connection', function (socket) {
  // Send it in a better format
  const players = discovery.players;

  if (players.length == 0) return;

  socket.emit('topology-change', players);
  discovery.getFavorites()
    .then((favorites) => {
      socket.emit('favorites', favorites);
    });

  socket.on('transport-state', function (data) {
    // find player based on uuid
    const player = discovery.getPlayerByUUID(data.uuid);

    if (!player) return;

    // invoke action
    //console.log(data)
    player[data.state]();
  });

  socket.on('group-volume', function (data) {
    // find player based on uuid
    const player = discovery.getPlayerByUUID(data.uuid);
    if (!player) return;

    // invoke action
    player.setGroupVolume(data.volume);
  });

  socket.on('group-management', function (data) {
    // find player based on uuid
    console.log(data)
    const player = discovery.getPlayerByUUID(data.player);
    if (!player) return;

    if (data.group == null) {
      player.becomeCoordinatorOfStandaloneGroup();
      return;
    }

    player.setAVTransport(`x-rincon:${data.group}`);
  });

  socket.on('play-favorite', function (data) {
    var player = discovery.getPlayerByUUID(data.uuid);
    if (!player) return;

    player.replaceWithFavorite(data.favorite)
      .then(() => player.play());
  });

  socket.on('queue', function (data) {
    loadQueue(data.uuid)
      .then(queue => {
        socket.emit('queue', { uuid: data.uuid, queue });
      });
  });

  socket.on('seek', function (data) {
    var player = discovery.getPlayerByUUID(data.uuid);
    if (player.avTransportUri.startsWith('x-rincon-queue')) {
      player.trackSeek(data.trackNo);
      return;
    }

    // Player is not using queue, so start queue first
    player.setAVTransport('x-rincon-queue:' + player.uuid + '#0')
      .then(() => player.trackSeek(data.trackNo))
      .then(() => player.play());
  });

  socket.on('playmode', function (data) {
    var player = discovery.getPlayerByUUID(data.uuid);
    for (var action in data.state) {
      player[action](data.state[action]);
    }
  });

  socket.on('volume', function (data) {
    var player = discovery.getPlayerByUUID(data.uuid);
    player.setVolume(data.volume);
  });

  socket.on('group-mute', function (data) {
    console.log(data)
    var player = discovery.getPlayerByUUID(data.uuid);
    if (data.mute)
      player.muteGroup();
    else
      player.unMuteGroup();
  });

  socket.on('mute', function (data) {
    var player = discovery.getPlayerByUUID(data.uuid);
    if (data.mute)
      player.mute();
    else
      player.unMute();
  });

  socket.on('track-seek', function (data) {
    var player = discovery.getPlayerByUUID(data.uuid);
    player.timeSeek(data.elapsed);
  });

  socket.on('search', function (data) {
    search(data.term, socket);
  });

  socket.on("error", function (e) {
    console.error(e);
  })
});

discovery.on('topology-change', function (data) {
  socketServer.sockets.emit('topology-change', discovery.players);
});

discovery.on('transport-state', function (data) {
  socketServer.sockets.emit('transport-state', data);
});

discovery.on('group-volume', function (data) {
  socketServer.sockets.emit('group-volume', data);
});

discovery.on('volume-change', function (data) {
  socketServer.sockets.emit('volume', data);
});

discovery.on('group-mute', function (data) {
  socketServer.sockets.emit('group-mute', data);
});

discovery.on('mute-change', function (data) {
  socketServer.sockets.emit('mute', data);
});

discovery.on('favorites', function (data) {
  socketServer.sockets.emit('favorites', data);
});

discovery.on('queue-change', function (player) {
  console.log('queue-changed', player.roomName);
  delete queues[player.uuid];
  loadQueue(player.uuid)
    .then(queue => {
      socketServer.sockets.emit('queue', { uuid: player.uuid, queue });
    });
});

function loadQueue(uuid) {
  if (queues[uuid]) {
    return Promise.resolve(queues[uuid]);
  }

  const player = discovery.getPlayerByUUID(uuid);
  return player.getQueue()
    .then(queue => {
      queues[uuid] = queue;
      return queue;
    });
}

function search(term, socket) {
  console.log('search for', term)
  var playerCycle = 0;
  var players = [];

  for (var i in discovery.players) {
    players.push(discovery.players[i]);
  }

  function getPlayer() {
    var player = players[playerCycle++ % players.length];
    return player;
  }

  var response = {};

  async.parallelLimit([
    function (callback) {
      var player = getPlayer();
      console.log('fetching from', player.address)
      player.browse('A:ARTIST:' + term, 0, 600, function (success, result) {
        console.log(success, result)
        response.byArtist = result;
        callback(null, 'artist');
      });
    },
    function (callback) {
      var player = getPlayer();
      console.log('fetching from', player.address)
      player.browse('A:TRACKS:' + term, 0, 600, function (success, result) {
        response.byTrack = result;
        callback(null, 'track');
      });
    },
    function (callback) {
      var player = getPlayer();
      console.log('fetching from', player.address)
      player.browse('A:ALBUM:' + term, 0, 600, function (success, result) {
        response.byAlbum = result;
        callback(null, 'album');
      });
    }
  ], players.length, function (err, result) {

    socket.emit('search-result', response);
  });
}

// Attach handler for socket.io

server.listen(settings.port);

console.log("http server listening on port", settings.port);
<|endoftext|>


<commit_before>var path = require('path');
var webpack = require('webpack');
var express = require('express');
var devMiddleware = require('webpack-dev-middleware');
var hotMiddleware = require('webpack-hot-middleware');

var config = require('./webpack.config');

var app = express();
var compiler = webpack(config);

app.use(devMiddleware(compiler, {
  publicPath: config.output.publicPath,
  historyApiFallback: true,
}));

app.use(hotMiddleware(compiler));

app.get('*', function (req, res) {
  res.sendFile(path.join(__dirname, 'index.html'));
});

app.listen(3000, function(err) {
  if (err) {
    return console.error(err);
  }

  console.log('Listening at http://localhost:3000/');
});
<commit_msg>Formatting<commit_after>var path = require('path');
var webpack = require('webpack');
var express = require('express');
var devMiddleware = require('webpack-dev-middleware');
var hotMiddleware = require('webpack-hot-middleware');
var config = require('./webpack.config');

var app = express();
var compiler = webpack(config);

app.use(devMiddleware(compiler, {
  publicPath: config.output.publicPath,
  historyApiFallback: true,
}));

app.use(hotMiddleware(compiler));

app.get('*', function (req, res) {
  res.sendFile(path.join(__dirname, 'index.html'));
});

app.listen(3000, function (err) {
  if (err) {
    return console.error(err);
  }

  console.log('Listening at http://localhost:3000/');
});
<|endoftext|>


<commit_before>
// Express - Helpers - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)

/**
 * JSON aliases.
 */

JSON.encode = JSON.stringify
JSON.decode = JSON.parse

/**
 * Return the directory name of the given _path_.
 *
 * @param  {string} path
 * @return {string}
 * @api public
 */

exports.dirname = function(path) {
  return path.split('/').slice(0, -1).join('/')
}

/**
 * Return the extension name of the given _path_,
 * or null when not present.
 *
 * @param  {string} path
 * @return {string}
 * @api public
 */

exports.extname = function(path) {
  if (path.lastIndexOf('.') < 0) return
  return path.slice(path.lastIndexOf('.') + 1)
}

/**
 * Escape special characters in _html_.
 *
 * @param  {string} html
 * @return {string}
 * @api public
 */

exports.escape = function(html) {
  if (html instanceof String)
    return html
      .replace(/&/g, '&')
      .replace(/"/g, '"')
      .replace(/</g, '<')
      .replace(/>/g, '>')
}

/**
 * Convert native array-like objects into an
 * array with optional _offset_.
 *
 * @param  {object} arr
 * @param  {int} offset
 * @return {array}
 * @api public
 */

exports.toArray = function(arr, offset) {
  return Array.prototype.slice.call(arr, offset)
}

/**
 * Escape RegExp _chars_ in _string_. Where _chars_
 * defaults to regular expression special characters.
 *
 * _chars_ should be a space delimited list of characters,
 * for example '[ ] ( )'.
 *
 * @param  {string} string
 * @param  {string} chars
 * @return {Type}
 * @api public
 */

exports.escapeRegexp = function(string, chars) {
  var specials = (chars || '/ . * + ? | ( ) [ ] { } \\').split(' ').join('|\\')
  return string.replace(new RegExp('(\\' + specials + ')', 'g'), '\\$1')
}

/**
 * Decode values in _params_.
 *
 * @param  {hash} params
 * @see parseNestedParams()
 * @api private
 */

function decode(params) {
  for (var key in params)
    params[key] = decodeURIComponent(params[key]).replace(/\+/g, ' ')
}

/**
 * Parse nested _params_.
 *
 * @param  {hash} params
 * @return {hash}
 * @see parseParams()
 * @api public
 */

var parseNestedParams = exports.parseNestedParams = function(params) {
  var parts, key
  decode(params)
  for (key in params)
    if (parts = key.split('['))
      if (parts.length > 1)
        for (var i = 0, prop = params, len = parts.length; i < len; ++i) {
          var name = parts[i].replace(']', '')
          if (i == len - 1)
            prop[name] = params[key],
            prop = params,
            delete params[key]
          else
            prop = prop[name] = prop[name] || {}
        }
  return params
}

/**
 * Parse params _string_ into a nested hash.
 *
 * @param  {string} string
 * @return {hash}
 * @api public
 */

exports.parseParams = function(string) {
  return parseNestedParams($(string.split('&')).reduce({}, function(params, pair){
    pair = pair.split('=')
    params[pair[0]] = pair[1]
    return params
  }))
}
<commit_msg>No need for var foo = exports.foo<commit_after>
// Express - Helpers - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)

/**
 * JSON aliases.
 */

JSON.encode = JSON.stringify
JSON.decode = JSON.parse

/**
 * Return the directory name of the given _path_.
 *
 * @param  {string} path
 * @return {string}
 * @api public
 */

exports.dirname = function(path) {
  return path.split('/').slice(0, -1).join('/')
}

/**
 * Return the extension name of the given _path_,
 * or null when not present.
 *
 * @param  {string} path
 * @return {string}
 * @api public
 */

exports.extname = function(path) {
  if (path.lastIndexOf('.') < 0) return
  return path.slice(path.lastIndexOf('.') + 1)
}

/**
 * Escape special characters in _html_.
 *
 * @param  {string} html
 * @return {string}
 * @api public
 */

exports.escape = function(html) {
  if (html instanceof String)
    return html
      .replace(/&/g, '&')
      .replace(/"/g, '"')
      .replace(/</g, '<')
      .replace(/>/g, '>')
}

/**
 * Convert native array-like objects into an
 * array with optional _offset_.
 *
 * @param  {object} arr
 * @param  {int} offset
 * @return {array}
 * @api public
 */

exports.toArray = function(arr, offset) {
  return Array.prototype.slice.call(arr, offset)
}

/**
 * Escape RegExp _chars_ in _string_. Where _chars_
 * defaults to regular expression special characters.
 *
 * _chars_ should be a space delimited list of characters,
 * for example '[ ] ( )'.
 *
 * @param  {string} string
 * @param  {string} chars
 * @return {Type}
 * @api public
 */

exports.escapeRegexp = function(string, chars) {
  var specials = (chars || '/ . * + ? | ( ) [ ] { } \\').split(' ').join('|\\')
  return string.replace(new RegExp('(\\' + specials + ')', 'g'), '\\$1')
}

/**
 * Decode values in _params_.
 *
 * @param  {hash} params
 * @see parseNestedParams()
 * @api private
 */

function decode(params) {
  for (var key in params)
    params[key] = decodeURIComponent(params[key]).replace(/\+/g, ' ')
}

/**
 * Parse nested _params_.
 *
 * @param  {hash} params
 * @return {hash}
 * @see parseParams()
 * @api public
 */

exports.parseNestedParams = function(params) {
  var parts, key
  decode(params)
  for (key in params)
    if (parts = key.split('['))
      if (parts.length > 1)
        for (var i = 0, prop = params, len = parts.length; i < len; ++i) {
          var name = parts[i].replace(']', '')
          if (i == len - 1)
            prop[name] = params[key],
            prop = params,
            delete params[key]
          else
            prop = prop[name] = prop[name] || {}
        }
  return params
}

/**
 * Parse params _string_ into a nested hash.
 *
 * @param  {string} string
 * @return {hash}
 * @api public
 */

exports.parseParams = function(string) {
  return exports.parseNestedParams($(string.split('&')).reduce({}, function(params, pair){
    pair = pair.split('=')
    params[pair[0]] = pair[1]
    return params
  }))
}
<|endoftext|>


<commit_before>var http = require('http');
var fs = require('fs');
var path = require('path');

http.createServer(function (request, response) {
    console.log('request starting...');

    var filePath = '.' + request.url;
    if (filePath == './')
        filePath = './index.html';

    var extname = path.extname(filePath);
    var contentType = 'text/html';
    switch (extname) {
        case '.js':
            contentType = 'text/javascript';
            break;
        case '.css':
            contentType = 'text/css';
            break;
        case '.json':
            contentType = 'application/json';
            break;
        case '.png':
            contentType = 'image/png';
            break;
        case '.jpg':
            contentType = 'image/jpg';
            break;
        case '.wav':
            contentType = 'audio/wav';
            break;
    }

    fs.readFile(filePath, function(error, content) {
        if (error) {
            if(error.code == 'ENOENT'){
                fs.readFile('./404.html', function(error, content) {
                    response.writeHead(200, { 'Content-Type': contentType });
                    response.end(content, 'utf-8');
                });
            }
            else {
                response.writeHead(500);
                response.end('Sorry, check with the site admin for error: '+error.code+' ..\n');
                response.end();
            }
        }
        else {
            response.writeHead(200, { 'Content-Type': contentType });
            response.end(content, 'utf-8');
        }
    });

}).listen(8000);
<commit_msg>new port<commit_after>var http = require('http');
var fs = require('fs');
var path = require('path');

http.createServer(function (request, response) {
    console.log('request starting...');

    var filePath = '.' + request.url;
    if (filePath == './')
        filePath = './index.html';

    var extname = path.extname(filePath);
    var contentType = 'text/html';
    switch (extname) {
        case '.js':
            contentType = 'text/javascript';
            break;
        case '.css':
            contentType = 'text/css';
            break;
        case '.json':
            contentType = 'application/json';
            break;
        case '.png':
            contentType = 'image/png';
            break;
        case '.jpg':
            contentType = 'image/jpg';
            break;
        case '.wav':
            contentType = 'audio/wav';
            break;
    }

    fs.readFile(filePath, function(error, content) {
        if (error) {
            if(error.code == 'ENOENT'){
                fs.readFile('./404.html', function(error, content) {
                    response.writeHead(200, { 'Content-Type': contentType });
                    response.end(content, 'utf-8');
                });
            }
            else {
                response.writeHead(500);
                response.end('Sorry, check with the site admin for error: '+error.code+' ..\n');
                response.end();
            }
        }
        else {
            response.writeHead(200, { 'Content-Type': contentType });
            response.end(content, 'utf-8');
        }
    });

}).listen(81234);
<|endoftext|>