-
Notifications
You must be signed in to change notification settings - Fork 26
/
Copy pathserver.js
112 lines (101 loc) · 3.55 KB
/
server.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
/**
* This is the server component - it starts a http server that treats all POST
* requests as data beacons from the instrumented client code, which it adds
* to the results global - this is persisted to results.json on the filesystem
*
* The server also responds to the following GET requests:
*
* / returns a static HTML report using the `report` component
* /data returns the `results` data as JSON
* /summary returns the `results` data reduced to mean values as JSON
*
* TODO: Add a GET route that acts as an instrumenting proxy for the JS code,
* to allow non-destructive instrumentation.
*
* @author Daniel Espeset <[email protected]>
* @copyright (c) 2014 Etsy, Inc.
**/
var http = require('http'),
qs = require('querystring'),
fs = require('fs'),
path = require('path'),
report = require('./report'),
url = require('url'),
spawn = require('child_process').spawn;
// Load persisted data or initialize it
try {
var results = require(path.resolve(__dirname, 'results'));
} catch(err) {
var results = {};
}
function handlePost(req, res) {
var body = "";
req.on('data', function(chunk) {
body += chunk;
});
req.on('end', function() {
var data = JSON.parse(qs.parse(body).results);
var result = results[req.headers['user-agent']] || ( results[req.headers['user-agent']] = {});
for ( var k in data ) {
result[k] = result[k] || { parse: [], exec: [] };
result[k].parse.push(data[k].parse);
result[k].exec.push(data[k].exec);
}
console.log((Object.keys(data).length) + " tested :: " + req.headers['user-agent']);
res.write(JSON.stringify({ success: true }));
res.end();
save();
});
}
function clone(obj) {
return JSON.parse(JSON.stringify(obj));
}
function handleGet(req, res) {
var parsedUrl = url.parse(req.url, true);
var pathArray = parsedUrl.pathname.replace(/^\/|\/$/g, '').split('/');
switch (pathArray[0]) {
case 'data':
res.write(JSON.stringify(results,null,' '));
res.end();
break;
case '':
res.write(report.generateHTML(report.buildReportData(clone(results))));
res.end();
break;
case 'summary':
res.write(JSON.stringify(report.buildReportData(clone(results))));
res.end();
break;
}
}
// Debounced persistence of `results` to filesystem
function save() {
clearTimeout(save.timer || -1);
save.timer = setTimeout(writeResults, 500);
}
// Write results to ./results.json TODO: make this configurable
function writeResults() {
fs.writeFileSync(path.resolve(__dirname, 'results.json'), JSON.stringify(results, null, ' '), 'utf8');
}
// Start the server, accepts option for port to listen on
function start(opts) {
var PORT = opts.p || opts.port || 8537;
http.createServer(function(req, res) {
// CORS headers, allow everything
res.setHeader('Access-Control-Allow-Origin', '*');
if (req.headers["Access-Control-Request-Headers"]) {
res.setHeader("Access-Control-Allow-Headers", req.headers["Access-Control-Request-Headers"]);
}
if (req.method === 'POST') {
handlePost(req, res);
} else {
handleGet(req, res);
}
}).listen(PORT);
// Ensure results have been persisted before exiting the process
process.on('exit', function() { writeResults(); });
console.log("Listening on port " + PORT);
}
module.exports = {
start: start
}