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 22// a duplex stream is just a stream that is both readable and writable. 23// Since JS doesn't have multiple prototype inheritance, this class 24// prototypically inherits from Readable, and then parasitically from 25// Writable. 26 27'use strict'; 28 29const { 30 ObjectDefineProperties, 31 ObjectKeys, 32 ObjectSetPrototypeOf, 33} = primordials; 34 35module.exports = Duplex; 36 37const Readable = require('_stream_readable'); 38const Writable = require('_stream_writable'); 39 40ObjectSetPrototypeOf(Duplex.prototype, Readable.prototype); 41ObjectSetPrototypeOf(Duplex, Readable); 42 43{ 44 // Allow the keys array to be GC'ed. 45 for (const method of ObjectKeys(Writable.prototype)) { 46 if (!Duplex.prototype[method]) 47 Duplex.prototype[method] = Writable.prototype[method]; 48 } 49} 50 51function Duplex(options) { 52 if (!(this instanceof Duplex)) 53 return new Duplex(options); 54 55 Readable.call(this, options); 56 Writable.call(this, options); 57 this.allowHalfOpen = true; 58 59 if (options) { 60 if (options.readable === false) 61 this.readable = false; 62 63 if (options.writable === false) 64 this.writable = false; 65 66 if (options.allowHalfOpen === false) { 67 this.allowHalfOpen = false; 68 this.once('end', onend); 69 } 70 } 71} 72 73ObjectDefineProperties(Duplex.prototype, { 74 75 destroyed: { 76 get() { 77 if (this._readableState === undefined || 78 this._writableState === undefined) { 79 return false; 80 } 81 return this._readableState.destroyed && this._writableState.destroyed; 82 }, 83 set(value) { 84 // Backward compatibility, the user is explicitly 85 // managing destroyed 86 if (this._readableState && this._writableState) { 87 this._readableState.destroyed = value; 88 this._writableState.destroyed = value; 89 } 90 } 91 }, 92 93 writableHighWaterMark: { 94 get() { 95 return this._writableState && this._writableState.highWaterMark; 96 } 97 }, 98 99 writableBuffer: { 100 get() { 101 return this._writableState && this._writableState.getBuffer(); 102 } 103 }, 104 105 writableLength: { 106 get() { 107 return this._writableState && this._writableState.length; 108 } 109 }, 110 111 writableFinished: { 112 get() { 113 return this._writableState ? this._writableState.finished : false; 114 } 115 }, 116 117 writableCorked: { 118 get() { 119 return this._writableState ? this._writableState.corked : 0; 120 } 121 }, 122 123 writableEnded: { 124 get() { 125 return this._writableState ? this._writableState.ending : false; 126 } 127 } 128}); 129 130// The no-half-open enforcer 131function onend() { 132 // If the writable side ended, then we're ok. 133 if (this._writableState.ended) 134 return; 135 136 // No more data can be written. 137 // But allow more writes to happen in this tick. 138 process.nextTick(onEndNT, this); 139} 140 141function onEndNT(self) { 142 self.end(); 143} 144