node-inspector/lib/debugger.js

162 строки
4.0 KiB
JavaScript
Исходник Обычный вид История

2010-11-07 03:36:45 +03:00
var Net = require('net'),
EventEmitter = require('events').EventEmitter,
Buffer = require('buffer').Buffer,
debugProtocol = require('debug')('node-inspector:protocol:v8-debug'),
2010-11-07 03:36:45 +03:00
callbackHandler = require('./callback').create();
function makeMessage() {
return {
headersDone: false,
headers: null,
contentLength: 0
};
}
///////////////////////////////////////////////////////////
// exports
2010-12-08 09:41:06 +03:00
exports.attachDebugger = function(port) {
var connected = false,
2010-11-07 03:36:45 +03:00
debugBuffer = '',
msg = false,
2010-11-07 03:36:45 +03:00
conn = Net.createConnection(port),
debugr,
offset,
contentLengthMatch,
lastError;
conn.setEncoding('utf8');
function parse() {
2010-11-07 03:36:45 +03:00
var b, obj;
if (msg && msg.headersDone) {
//parse body
2010-11-07 03:36:45 +03:00
if (Buffer.byteLength(debugBuffer) >= msg.contentLength) {
b = new Buffer(debugBuffer);
msg.body = b.toString('utf8', 0, msg.contentLength);
2010-11-07 03:36:45 +03:00
debugBuffer = b.toString('utf8', msg.contentLength, b.length);
if (msg.body.length > 0) {
2010-11-07 03:36:45 +03:00
obj = JSON.parse(msg.body);
if (typeof obj.running === 'boolean') {
debugr.isRunning = obj.running;
}
if (obj.type === 'response' && obj.request_seq > 0) {
debugProtocol('response: ' + msg.body);
2010-11-07 03:36:45 +03:00
callbackHandler.processResponse(obj.request_seq, [obj]);
}
2010-10-28 09:17:06 +04:00
else if (obj.type === 'event') {
debugProtocol('event: ' + msg.body);
if (['break', 'exception'].indexOf(obj.event) > -1) {
debugr.isRunning = false;
}
2010-10-28 09:17:06 +04:00
debugr.emit(obj.event, obj);
}
else {
debugProtocol('unknown: ' + msg.body);
}
}
msg = false;
parse();
}
return;
}
if (!msg) {
msg = makeMessage();
}
2010-11-07 03:36:45 +03:00
offset = debugBuffer.indexOf('\r\n\r\n');
if (offset > 0) {
msg.headersDone = true;
2010-11-07 03:36:45 +03:00
msg.headers = debugBuffer.substr(0, offset + 4);
contentLengthMatch = /Content-Length: (\d+)/.exec(msg.headers);
if (contentLengthMatch[1]) {
msg.contentLength = parseInt(contentLengthMatch[1], 10);
}
else {
2010-09-11 03:59:18 +04:00
console.warn('no Content-Length');
}
2010-11-07 03:36:45 +03:00
debugBuffer = debugBuffer.slice(offset + 4);
parse();
}
}
2010-11-07 03:36:45 +03:00
debugr = Object.create(EventEmitter.prototype, {
isRunning: { writable: true, value: true },
send: {
2010-12-08 09:41:06 +03:00
value: function(data)
{
debugProtocol('request: ' + data);
if (connected) {
2010-11-07 03:36:45 +03:00
conn.write('Content-Length: ' + data.length + '\r\n\r\n' + data);
}
}
},
request: {
2010-12-08 09:41:06 +03:00
value: function(command, params, callback) {
var msg = {
seq: 0,
type: 'request',
command: command
};
2010-11-07 03:36:45 +03:00
if (typeof callback == 'function') {
msg.seq = callbackHandler.wrap(callback);
}
if (params) {
Object.keys(params).forEach(function(key) {
msg[key] = params[key];
});
}
this.send(JSON.stringify(msg));
}
},
close: {
2010-12-08 09:41:06 +03:00
value: function()
{
conn.end();
}
2010-09-11 03:59:18 +04:00
},
connected: {
get: function() { return connected; }
}
});
2010-12-08 09:41:06 +03:00
conn.on('connect', function() {
connected = true;
debugr.emit('connect');
});
2010-12-08 09:41:06 +03:00
conn.on('data', function(data) {
2010-11-07 03:36:45 +03:00
debugBuffer += data;
parse();
});
2010-12-08 09:41:06 +03:00
conn.on('error', function(e) {
if (e.code == 'ECONNREFUSED') {
e.helpString = 'Is node running with --debug port ' + port + '?';
} else if (e.code == 'ECONNRESET') {
e.helpString = 'Check there is no other debugger client attached to port ' + port + '.';
}
lastError = e.toString();
if (e.helpString) {
lastError += '. ' + e.helpString;
}
debugr.emit('error', e);
});
2010-12-08 09:41:06 +03:00
conn.on('end', function() {
debugr.close();
});
2010-12-08 09:41:06 +03:00
conn.on('close', function() {
connected = false;
debugr.emit('close', lastError || 'Debugged process exited.');
});
return debugr;
};