server.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. var settings = require('./server_config/settings.json');
  2. var fs = require('fs');
  3. var async = require('async');
  4. var express = require('express');
  5. var app = express();
  6. var server = require('http').createServer(app);
  7. var io = require('socket.io').listen(server);
  8. var bodyParser = require('body-parser');
  9. var phantomas = require('phantomas');
  10. app.use(bodyParser.urlencoded({ extended: false }));
  11. // Home page
  12. app.get('/', function(req, res) {
  13. async.parallel({
  14. htmlTemplate: function(callback) {
  15. fs.readFile('./app/views/index.html', {encoding: 'utf8'}, callback);
  16. }
  17. }, function(err, results) {
  18. res.setHeader('Content-Type', 'text/html');
  19. res.send(results.htmlTemplate);
  20. });
  21. });
  22. // Waiting queue page
  23. app.post('/launchTest', function(req, res) {
  24. // Generate test id
  25. var testId = (Date.now()*1000 + Math.round(Math.random()*1000)).toString(36);
  26. var resultsPath = 'results/' + testId;
  27. var phantomasResultsPath = resultsPath + '/results.json';
  28. var url = req.body.url;
  29. if (url.indexOf('http://') !== 0 && url.indexOf('https://') !== 0) {
  30. url = 'http://' + url;
  31. }
  32. async.waterfall([
  33. function htmlTemplate(callback) {
  34. fs.readFile('./app/views/launchTest.html', {encoding: 'utf8'}, callback);
  35. },
  36. function sendResponse(html, callback) {
  37. html = html.replace('%%TEST_URL%%', url);
  38. html = html.replace('%%TEST_ID%%', testId);
  39. res.setHeader('Content-Type', 'text/html');
  40. res.send(html);
  41. callback();
  42. },
  43. function createFolder(callback) {
  44. // Create results folder
  45. fs.mkdir(resultsPath, callback);
  46. },
  47. function executePhantomas(callback) {
  48. var options = {
  49. timeout: 60,
  50. 'js-deep-analysis': false,
  51. reporter: 'json:pretty',
  52. 'skip-modules': [
  53. 'ajaxRequests',
  54. 'alerts',
  55. 'cacheHits',
  56. 'caching',
  57. 'console',
  58. 'cookies',
  59. 'documentHeight',
  60. 'domains',
  61. 'domComplexity',
  62. 'domMutations',
  63. 'domQueries',
  64. 'filmStrip',
  65. 'jQuery',
  66. 'jserrors',
  67. 'har',
  68. 'headers',
  69. 'localStorage',
  70. 'mainRequest',
  71. 'pageSource',
  72. 'redirects',
  73. 'requestsStats',
  74. 'screenshot',
  75. 'staticAssets',
  76. 'timeToFirst',
  77. 'waitForSelector'
  78. ].join(','),
  79. 'include-dirs': [
  80. 'phantomas_custom/core',
  81. 'phantomas_custom/modules'
  82. ].join(',')
  83. };
  84. console.log('Adding test ' + testId + ' on ' + url + ' to the queue');
  85. var task = {
  86. testId: testId,
  87. url: url,
  88. options: options
  89. };
  90. console.log(JSON.stringify(task, null, 4));
  91. taskQueue.push(task, callback);
  92. },
  93. function writeResults(json, resultsObject, callback) {
  94. console.log('Saving Phantomas results file to ' + phantomasResultsPath);
  95. fs.writeFile(phantomasResultsPath, JSON.stringify(json, null, 4), callback);
  96. }
  97. ], function(err) {
  98. if (err) {
  99. console.log('An error occured while launching the phantomas test : ', err);
  100. fs.writeFile(phantomasResultsPath, JSON.stringify({url: url, error: err}, null, 4), function(err) {
  101. if (err) {
  102. console.log('Could not even write an error message on file ' + phantomasResultsPath);
  103. console.log(err);
  104. }
  105. });
  106. }
  107. });
  108. });
  109. // Results page
  110. app.get('/results/:testId', function(req, res) {
  111. var testId = req.params.testId;
  112. var resultsPath = 'results/' + testId;
  113. var phantomasResultsPath = resultsPath + '/results.json';
  114. console.log('Opening test ' + testId + ' results as HTML');
  115. async.parallel({
  116. htmlTemplate: function(callback) {
  117. fs.readFile('./app/views/results.html', {encoding: 'utf8'}, callback);
  118. },
  119. phantomasResults: function(callback) {
  120. fs.readFile(phantomasResultsPath, {encoding: 'utf8'}, callback);
  121. }
  122. }, function(err, results) {
  123. if (err) {
  124. console.log(err);
  125. return res.status(404).send('Sorry, test not found...');
  126. }
  127. var html = results.htmlTemplate;
  128. html = html.replace('%%RESULTS%%', results.phantomasResults);
  129. res.setHeader('Content-Type', 'text/html');
  130. res.send(html);
  131. });
  132. });
  133. // Static files
  134. app.use('/public', express.static(__dirname + '/app/public'));
  135. app.use('/bower_components', express.static(__dirname + '/bower_components'));
  136. // Socket.io
  137. io.on('connection', function(socket){
  138. socket.on('waiting', function(testId) {
  139. console.log('User waiting for test id ' + testId);
  140. socket.testId = testId;
  141. // Check task position in queue
  142. var positionInQueue = -1;
  143. if (taskQueue.length() > 0) {
  144. taskQueue.tasks.forEach(function(task, index) {
  145. if (task.data.testId === testId) {
  146. positionInQueue = index;
  147. }
  148. });
  149. }
  150. if (positionInQueue >= 0) {
  151. socket.emit('position', positionInQueue);
  152. } else if (currentTask && currentTask.testId === testId) {
  153. socket.emit('running');
  154. } else {
  155. // Find in results files
  156. var exists = fs.exists('results/' + testId + '/results.json', function(exists) {
  157. if (exists) {
  158. // TODO : use eventEmitter to make sure the file is completly written on disk
  159. setTimeout(function() {
  160. socket.emit('complete');
  161. }, 1000);
  162. } else {
  163. socket.emit('404');
  164. }
  165. });
  166. }
  167. });
  168. });
  169. // Creating a queue and defining the worker function
  170. var currentTask = null;
  171. var taskQueue = async.queue(function queueWorker(task, callback) {
  172. currentTask = task;
  173. console.log('Starting test ' + task.testId);
  174. // It's time to launch the test!!!
  175. phantomas(task.url, task.options, function(err, json, results) {
  176. console.log('Test ' + task.testId + ' complete');
  177. currentTask = null;
  178. callback(err, json, results);
  179. });
  180. });
  181. // Launch the server
  182. server.listen(settings.serverPort, function() {
  183. console.log('Listening on port %d', server.address().port);
  184. });