debugger.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. var Net = require('net'),
  2. Protocol = require('_debugger').Protocol,
  3. inherits = require('util').inherits,
  4. EventEmitter = require('events').EventEmitter,
  5. debugProtocol = require('debug')('node-inspector:protocol:v8-debug'),
  6. callbackHandler = require('./callback').create();
  7. /**
  8. * @param {Number} port
  9. */
  10. function Debugger(port){
  11. this._port = port;
  12. this._connected = false;
  13. this._connection = null;
  14. this._lastError = null;
  15. this._setupConnection();
  16. }
  17. inherits(Debugger, EventEmitter);
  18. Object.defineProperties(Debugger.prototype, {
  19. /** @type {boolean} */
  20. isRunning: { writable: true, value: true },
  21. /** @type {boolean} */
  22. connected: {
  23. get: function() {
  24. return this._connected;
  25. }
  26. }
  27. });
  28. Debugger.prototype._setupConnection = function() {
  29. var connection = Net.createConnection(this._port),
  30. protocol = new Protocol();
  31. protocol.onResponse = this._processResponse.bind(this);
  32. connection
  33. .on('connect', this._onConnectionOpen.bind(this))
  34. .on('data', protocol.execute.bind(protocol))
  35. .on('error', this._onConnectionError.bind(this))
  36. .on('end', this.close.bind(this))
  37. .on('close', this._onConnectionClose.bind(this))
  38. .setEncoding('utf8');
  39. this._connection = connection;
  40. };
  41. Debugger.prototype._onConnectionOpen = function() {
  42. this._connected = true;
  43. this.emit('connect');
  44. };
  45. /**
  46. * @param {Error} err
  47. */
  48. Debugger.prototype._onConnectionError = function(err) {
  49. if (err.code == 'ECONNREFUSED') {
  50. err.helpString = 'Is node running with --debug port ' + this._port + '?';
  51. } else if (err.code == 'ECONNRESET') {
  52. err.helpString = 'Check there is no other debugger client attached to port ' + this._port + '.';
  53. }
  54. this._lastError = err.toString();
  55. if (err.helpString) {
  56. this._lastError += '. ' + err.helpString;
  57. }
  58. this.emit('error', err);
  59. };
  60. Debugger.prototype._onConnectionClose = function(hadError) {
  61. this.emit('close', hadError ? this._lastError : 'Debugged process exited.');
  62. this._port = null;
  63. this._connected = false;
  64. this._connection = null;
  65. this._lastError = null;
  66. };
  67. Debugger.prototype._processResponse = function(message) {
  68. var obj = message.body;
  69. if (typeof obj.running === 'boolean') {
  70. this.isRunning = obj.running;
  71. }
  72. if (obj.type === 'response' && obj.request_seq > 0) {
  73. debugProtocol('response: ' + message.body);
  74. callbackHandler.processResponse(obj.request_seq, [obj]);
  75. }
  76. else if (obj.type === 'event') {
  77. debugProtocol('event: ' + message.body);
  78. if (['break', 'exception'].indexOf(obj.event) > -1) {
  79. this.isRunning = false;
  80. }
  81. this.emit(obj.event, obj);
  82. }
  83. else {
  84. debugProtocol('unknown: ' + message.body);
  85. }
  86. };
  87. /**
  88. * @param {string} data
  89. */
  90. Debugger.prototype.send = function(data) {
  91. debugProtocol('request: ' + data);
  92. if (this.connected) {
  93. this._connection.write('Content-Length: ' + Buffer.byteLength(data, 'utf8') + '\r\n\r\n' + data);
  94. }
  95. };
  96. /**
  97. * @param {string} command
  98. * @param {Object} params
  99. * @param {function} callback
  100. */
  101. Debugger.prototype.request = function(command, params, callback) {
  102. var message = {
  103. seq: 0,
  104. type: 'request',
  105. command: command
  106. };
  107. if (typeof callback === 'function') {
  108. message.seq = callbackHandler.wrap(callback);
  109. }
  110. if (params) {
  111. Object.keys(params).forEach(function(key) {
  112. message[key] = params[key];
  113. });
  114. }
  115. this.send(JSON.stringify(message));
  116. };
  117. /**
  118. */
  119. Debugger.prototype.close = function() {
  120. this._connection.end();
  121. };
  122. /**
  123. * @param {Number} port
  124. * @type {Debugger}
  125. */
  126. module.exports.attachDebugger = function(port) {
  127. return new Debugger(port);
  128. };