-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathserver.js
130 lines (106 loc) · 3.48 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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// import needed libraries (installed with npm)
var express = require('express');
var bodyParser = require('body-parser');
var events = require('events');
var child_process = require('child_process');
var tmp = require('tmp');
var fs = require('fs-extra');
var EventEmitter = require('events').EventEmitter;
var util = require('util');
// var multer = require('multer');
var app = express();
// really annoyed that express doesn't do this by default
app.use(bodyParser.json()); // to support JSON-encoded bodies
app.use(bodyParser.urlencoded({ // to support URL-encoded bodies
extended: true
}));
// tell express to print requests in the console as they come in
app.use(require('morgan')('tiny'));
// for uploading files
// app.use(multer({ dest: './saved_data/uploads/'}));
// serve static files
app.use(express.static(__dirname + '/public'));
// tell express how to handle requests
app.get('/', function(req, res) {
res.sendFile('public/index.html');
});
app.post('/run_python', function(req, res) {
tmp.dir(function(err, path, cleanupCallback) {
if (err) throw err;
console.log("Dir: ", path);
// ugh, that callback christmas tree... should have written in Go
var code_path = path + '/code.py'
var log_call_path = path + '/log_call.py'
fs.copy('src/Runtime/log_call.py', log_call_path, function (err) {
if (err) return console.error(err)
var code = req.body.code;
console.log('CODE:', code);
fs.writeFile(code_path, code, function(err) {
if(err) throw err;
var stdout_messages = [];
var stderr_messages = [];
var python = child_process.spawn('python', [code_path]);
// TODO: implement f*#@$ing framed protocol
var f_buf = new FramedBuffer();
python.stdout.on('data', function(line) {
console.log('python out:', line);
f_buf.push(line);
});
python.stderr.setEncoding('utf8');
python.stderr.on('data', function(data) {
var line = data.trim();
console.log('python err:', line);
stderr_messages.push(line);
});
f_buf.on('message', function(msg) {
stdout_messages.push(JSON.parse(msg));
});
python.on('close', function(code, signal) {
console.log('exit code: ', code);
if(code == 0) {
res.status(200);
res.send(stdout_messages);
} else {
res.status(500);
res.send(stderr_messages);
}
console.log('contents:', fs.readdirSync(path));
fs.removeSync(path)
});
});
});
});
});
// TODO: this must be in a package somewhere...
function FramedBuffer() {
this.buffer = '';
this.state = 'beginning';
this.length_left = 0;
return this;
}
util.inherits(FramedBuffer, EventEmitter);
FramedBuffer.prototype.push = function(buf) {
if(buf.length == 0) {
return;
}
if(this.state === 'beginning') {
var length = buf.readInt32LE();
this.length_left = length;
buf = buf.slice(4);
this.state = 'reading';
}
var chunk_length = Math.min(this.length_left, buf.length);
var this_chunk = buf.toString('utf8', 0, chunk_length);
this.buffer += this_chunk;
this.length_left -= chunk_length;
if(this.length_left === 0) {
this.state = 'beginning';
this.emit('message', this.buffer);
this.buffer = '';
this.push(buf.slice(chunk_length));
}
}
// start it up
app.listen(3000, function() {
console.log('listening on http://localhost:3000/');
});