1'use strict'; // undocumented cb() API, needed for core, not for public API 2 3function destroy(err, cb) { 4 var _this = this; 5 6 var readableDestroyed = this._readableState && this._readableState.destroyed; 7 var writableDestroyed = this._writableState && this._writableState.destroyed; 8 9 if (readableDestroyed || writableDestroyed) { 10 if (cb) { 11 cb(err); 12 } else if (err) { 13 if (!this._writableState) { 14 process.nextTick(emitErrorNT, this, err); 15 } else if (!this._writableState.errorEmitted) { 16 this._writableState.errorEmitted = true; 17 process.nextTick(emitErrorNT, this, err); 18 } 19 } 20 21 return this; 22 } // we set destroyed to true before firing error callbacks in order 23 // to make it re-entrance safe in case destroy() is called within callbacks 24 25 26 if (this._readableState) { 27 this._readableState.destroyed = true; 28 } // if this is a duplex stream mark the writable part as destroyed as well 29 30 31 if (this._writableState) { 32 this._writableState.destroyed = true; 33 } 34 35 this._destroy(err || null, function (err) { 36 if (!cb && err) { 37 if (!_this._writableState) { 38 process.nextTick(emitErrorAndCloseNT, _this, err); 39 } else if (!_this._writableState.errorEmitted) { 40 _this._writableState.errorEmitted = true; 41 process.nextTick(emitErrorAndCloseNT, _this, err); 42 } else { 43 process.nextTick(emitCloseNT, _this); 44 } 45 } else if (cb) { 46 process.nextTick(emitCloseNT, _this); 47 cb(err); 48 } else { 49 process.nextTick(emitCloseNT, _this); 50 } 51 }); 52 53 return this; 54} 55 56function emitErrorAndCloseNT(self, err) { 57 emitErrorNT(self, err); 58 emitCloseNT(self); 59} 60 61function emitCloseNT(self) { 62 if (self._writableState && !self._writableState.emitClose) return; 63 if (self._readableState && !self._readableState.emitClose) return; 64 self.emit('close'); 65} 66 67function undestroy() { 68 if (this._readableState) { 69 this._readableState.destroyed = false; 70 this._readableState.reading = false; 71 this._readableState.ended = false; 72 this._readableState.endEmitted = false; 73 } 74 75 if (this._writableState) { 76 this._writableState.destroyed = false; 77 this._writableState.ended = false; 78 this._writableState.ending = false; 79 this._writableState.finalCalled = false; 80 this._writableState.prefinished = false; 81 this._writableState.finished = false; 82 this._writableState.errorEmitted = false; 83 } 84} 85 86function emitErrorNT(self, err) { 87 self.emit('error', err); 88} 89 90function errorOrDestroy(stream, err) { 91 // We have tests that rely on errors being emitted 92 // in the same tick, so changing this is semver major. 93 // For now when you opt-in to autoDestroy we allow 94 // the error to be emitted nextTick. In a future 95 // semver major update we should change the default to this. 96 var rState = stream._readableState; 97 var wState = stream._writableState; 98 if (rState && rState.autoDestroy || wState && wState.autoDestroy) stream.destroy(err);else stream.emit('error', err); 99} 100 101module.exports = { 102 destroy: destroy, 103 undestroy: undestroy, 104 errorOrDestroy: errorOrDestroy 105};