• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright Joyent, Inc. and other Node contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the
5// "Software"), to deal in the Software without restriction, including
6// without limitation the rights to use, copy, modify, merge, publish,
7// distribute, sublicense, and/or sell copies of the Software, and to permit
8// persons to whom the Software is furnished to do so, subject to the
9// following conditions:
10//
11// The above copyright notice and this permission notice shall be included
12// in all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20// USE OR OTHER DEALINGS IN THE SOFTWARE.
21// a duplex stream is just a stream that is both readable and writable.
22// Since JS doesn't have multiple prototypal inheritance, this class
23// prototypally inherits from Readable, and then parasitically from
24// Writable.
25'use strict';
26/*<replacement>*/
27
28var objectKeys = Object.keys || function (obj) {
29  var keys = [];
30
31  for (var key in obj) {
32    keys.push(key);
33  }
34
35  return keys;
36};
37/*</replacement>*/
38
39
40module.exports = Duplex;
41
42var Readable = require('./_stream_readable');
43
44var Writable = require('./_stream_writable');
45
46require('inherits')(Duplex, Readable);
47
48{
49  // Allow the keys array to be GC'ed.
50  var keys = objectKeys(Writable.prototype);
51
52  for (var v = 0; v < keys.length; v++) {
53    var method = keys[v];
54    if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method];
55  }
56}
57
58function Duplex(options) {
59  if (!(this instanceof Duplex)) return new Duplex(options);
60  Readable.call(this, options);
61  Writable.call(this, options);
62  this.allowHalfOpen = true;
63
64  if (options) {
65    if (options.readable === false) this.readable = false;
66    if (options.writable === false) this.writable = false;
67
68    if (options.allowHalfOpen === false) {
69      this.allowHalfOpen = false;
70      this.once('end', onend);
71    }
72  }
73}
74
75Object.defineProperty(Duplex.prototype, 'writableHighWaterMark', {
76  // making it explicit this property is not enumerable
77  // because otherwise some prototype manipulation in
78  // userland will fail
79  enumerable: false,
80  get: function get() {
81    return this._writableState.highWaterMark;
82  }
83});
84Object.defineProperty(Duplex.prototype, 'writableBuffer', {
85  // making it explicit this property is not enumerable
86  // because otherwise some prototype manipulation in
87  // userland will fail
88  enumerable: false,
89  get: function get() {
90    return this._writableState && this._writableState.getBuffer();
91  }
92});
93Object.defineProperty(Duplex.prototype, 'writableLength', {
94  // making it explicit this property is not enumerable
95  // because otherwise some prototype manipulation in
96  // userland will fail
97  enumerable: false,
98  get: function get() {
99    return this._writableState.length;
100  }
101}); // the no-half-open enforcer
102
103function onend() {
104  // If the writable side ended, then we're ok.
105  if (this._writableState.ended) return; // no more data can be written.
106  // But allow more writes to happen in this tick.
107
108  process.nextTick(onEndNT, this);
109}
110
111function onEndNT(self) {
112  self.end();
113}
114
115Object.defineProperty(Duplex.prototype, 'destroyed', {
116  // making it explicit this property is not enumerable
117  // because otherwise some prototype manipulation in
118  // userland will fail
119  enumerable: false,
120  get: function get() {
121    if (this._readableState === undefined || this._writableState === undefined) {
122      return false;
123    }
124
125    return this._readableState.destroyed && this._writableState.destroyed;
126  },
127  set: function set(value) {
128    // we ignore the value if the stream
129    // has not been initialized yet
130    if (this._readableState === undefined || this._writableState === undefined) {
131      return;
132    } // backward compatibility, the user is explicitly
133    // managing destroyed
134
135
136    this._readableState.destroyed = value;
137    this._writableState.destroyed = value;
138  }
139});