• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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};