Sequence.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. var Util = require('util');
  2. var EventEmitter = require('events').EventEmitter;
  3. var Packets = require('../packets');
  4. var ErrorConstants = require('../constants/errors');
  5. var listenerCount = EventEmitter.listenerCount
  6. || function(emitter, type){ return emitter.listeners(type).length; };
  7. module.exports = Sequence;
  8. Util.inherits(Sequence, EventEmitter);
  9. function Sequence(options, callback) {
  10. if (typeof options === 'function') {
  11. callback = options;
  12. options = {};
  13. }
  14. EventEmitter.call(this);
  15. options = options || {};
  16. this._callback = callback;
  17. this._callSite = null;
  18. this._ended = false;
  19. this._timeout = options.timeout;
  20. // For Timers
  21. this._idleNext = null;
  22. this._idlePrev = null;
  23. this._idleStart = null;
  24. this._idleTimeout = undefined;
  25. this._repeat = null;
  26. }
  27. Sequence.determinePacket = function(byte) {
  28. switch (byte) {
  29. case 0x00: return Packets.OkPacket;
  30. case 0xfe: return Packets.EofPacket;
  31. case 0xff: return Packets.ErrorPacket;
  32. }
  33. };
  34. Sequence.prototype.hasErrorHandler = function() {
  35. return Boolean(this._callback) || listenerCount(this, 'error') > 1;
  36. };
  37. Sequence.prototype._packetToError = function(packet) {
  38. var code = ErrorConstants[packet.errno] || 'UNKNOWN_CODE_PLEASE_REPORT';
  39. var err = new Error(code + ': ' + packet.message);
  40. err.code = code;
  41. err.errno = packet.errno;
  42. err.sqlState = packet.sqlState;
  43. return err;
  44. };
  45. Sequence.prototype._addLongStackTrace = function(err) {
  46. if (!this._callSite) {
  47. return;
  48. }
  49. var delimiter = '\n --------------------\n' ;
  50. if (err.stack.indexOf(delimiter) > -1) {
  51. return;
  52. }
  53. err.stack += delimiter + this._callSite.stack.replace(/.+\n/, '');
  54. };
  55. Sequence.prototype.end = function(err) {
  56. if (this._ended) {
  57. return;
  58. }
  59. this._ended = true;
  60. if (err) {
  61. this._addLongStackTrace(err);
  62. }
  63. // Without this we are leaking memory. This problem was introduced in
  64. // 8189925374e7ce3819bbe88b64c7b15abac96b16. I suspect that the error object
  65. // causes a cyclic reference that the GC does not detect properly, but I was
  66. // unable to produce a standalone version of this leak. This would be a great
  67. // challenge for somebody interested in difficult problems : )!
  68. this._callSite = null;
  69. // try...finally for exception safety
  70. try {
  71. if (err) {
  72. this.emit('error', err);
  73. }
  74. } finally {
  75. try {
  76. if (this._callback) {
  77. this._callback.apply(this, arguments);
  78. }
  79. } finally {
  80. this.emit('end');
  81. }
  82. }
  83. };
  84. Sequence.prototype['OkPacket'] = function(packet) {
  85. this.end(null, packet);
  86. };
  87. Sequence.prototype['ErrorPacket'] = function(packet) {
  88. this.end(this._packetToError(packet));
  89. };
  90. // Implemented by child classes
  91. Sequence.prototype.start = function() {};
  92. Sequence.prototype._onTimeout = function _onTimeout() {
  93. this.emit('timeout');
  94. };