-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.js
98 lines (78 loc) · 3.09 KB
/
index.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
var spawn = require('child_process').spawn
, EventEmitter = require('events').EventEmitter
;
function sleepyhollow() {
// the modified event-emitter bridge
var sleepyhollow = new EventEmitter();
_emit = sleepyhollow.emit;
sleepyhollow.emit = function(event, message) {
if (event !== "ack") write({ event: event, message : message });
_emit.apply(sleepyhollow, Array.prototype.slice.call(arguments, 0));
}
// the phantomjs process
var args = Array.prototype.slice.call(arguments, 0);
var phantomjs = spawn.apply(null, ['phantomjs', args]);
// if node goes down, don't leave phantom zombied
var exited = false;
process.on('exit', function() {
if (!exited) process.kill(phantomjs.pid, 'SIGINT');
});
// special listener to the child process lifecycle
phantomjs.on('exit', function() {
exited = true;
sleepyhollow.emit('exit');
});
// we use the stderr channel for communication because we listen on
// stdout for errors and debugging statements
phantomjs.stderr.on('data', function(data) {
data.toString().split('\n').forEach(read);
});
phantomjs.stdout.on('data', function(data) {
var errorHandlers = sleepyhollow.listeners('error');
if (errorHandlers && errorHandlers.length > 0)
sleepyhollow.emit('error', data.toString());
});
// the writing mechanism, which drains periodically
var writeBuffer = [];
function write(obj) { writeBuffer.push(JSON.stringify(obj)); }
function _write() {
phantomjs.stdin.write(writeBuffer.join("\v") + "\n");
writeBuffer = [];
}
// the read mechanism that selectively writes
var readBuffer = [];
function read(data) {
// parse the message to ensure phantom sent correctly
if (!data) return;
try { data = JSON.parse(data) }
catch (e) { console.log(e, data); throw new Error(e); }
// if the message has already been converted into a full object,
// re-stringify it to be parsed later
if (typeof data.message == "object") {
data.message = JSON.stringify(data.message);
}
// if there's a message, push onto the readBuffer
if (data.message) readBuffer.push(data.message);
// emit if this data is not multipart or it's the last message
if (!data.isMultipart || data.isEOF) {
// build up the args to emit
var args = [data.event];
// join up the buffer, silently fail if not an object
var message = readBuffer.join('');
if (message) {
try { message = JSON.parse(message); }
catch (e) { console.log(e, message); throw new Error(e); }
args.push(message);
}
// emit the event with variable arguments
_emit.apply(sleepyhollow, args);
// reset the buffer
readBuffer = [];
}
if (data.event == "ack") return;
write({ "event": "ack" });
_write();
}
return sleepyhollow;
}
module.exports = sleepyhollow;