Permalink
Browse files

Add a Duplex class

A place to put the allowHalfOpen logic.
  • Loading branch information...
isaacs committed Oct 2, 2012
1 parent 9adeb65 commit 9a0662bbdbdd8cf7d7bff7173b88fe804b4d7572
Showing with 99 additions and 14 deletions.
  1. +36 −1 README.md
  2. +60 −0 duplex.js
  3. +3 −13 transform.js
View
@@ -9,7 +9,7 @@ This is an abstract class designed to be extended. It also provides a
streams that have the "readable stream" interface of Node 0.8 and
before.
-Note that Transform, Writable, and PassThrough streams are also
+Note that Duplex, Transform, Writable, and PassThrough streams are also
provided as base classes. See the full API details below.
## Justification
@@ -379,6 +379,41 @@ down a socket or close a file descriptor. At this time, the writable
stream may be safely disposed. Its mission in life has been
accomplished.
+## Class: Duplex
+
+A base class for Duplex streams (ie, streams that are both readable
+and writable).
+
+Since JS doesn't have multiple prototypal inheritance, this class
+prototypally inherits from Readable, and then parasitically from
+Writable. It is thus up to the user to implement both the lowlevel
+`_read(n,cb)` method as well as the lowlevel `_write(chunk,cb)`
+method on extension duplex classes.
+
+For cases where the written data is transformed into the output, it
+may be simpler to use the `Transform` class instead.
+
+### new Duplex(options)
+
+* `options` {Object} Passed to both the Writable and Readable
+ constructors.
+
+Make sure to call the `Duplex` constructor in your extension
+classes, or else the stream will not be properly initialized.
+
+If `options.allowHalfOpen` is set to the value `false`, then the
+stream will automatically end the readable side when the writable
+side ends, and vice versa.
+
+### duplex.allowHalfOpen
+
+* {Boolean} Default = `true`
+
+Set this flag to either `true` or `false` to determine whether or not
+to automatically close the writable side when the readable side ends,
+and vice versa.
+
+
## Class: Transform
A duplex (ie, both readable and writable) stream that is designed to
View
@@ -0,0 +1,60 @@
+// a duplex stream is just a stream that is both readable and writable.
+// Since JS doesn't have multiple prototypal inheritance, this class
+// prototypally inherits from Readable, and then parasitically from
+// Writable.
+
+module.exports = Duplex;
+var util = require('util');
+var Readable = require('./readable.js');
+var Writable = require('./writable.js');
+
+util.inherits(Duplex, Readable);
+
+Object.keys(Writable.prototype).forEach(function(method) {
+ if (!Duplex.prototype[method])
+ Duplex.prototype[method] = Writable.prototype[method];
+});
+
+function Duplex(options) {
+ Readable.call(this, options);
+ Writable.call(this, options);
+
+ this.allowHalfOpen = true;
+ if (options && options.allowHalfOpen === false)
+ this.allowHalfOpen = false;
+
+ this.once('finish', onfinish);
+ this.once('end', onend);
+}
+
+// the no-half-open enforcers.
+function onfinish() {
+ // if we allow half-open state, or if the readable side ended,
+ // then we're ok.
+ if (this.allowHalfOpen || this._readableState.ended)
+ return;
+
+ // mark that we're done.
+ this._readableState.ended = true;
+
+ // tell the user
+ if (this._readableState.length === 0)
+ this.emit('end');
+ else
+ this.emit('readable');
+}
+
+function onend() {
+ // if we allow half-open state, or if the writable side ended,
+ // then we're ok.
+ if (this.allowHalfOpen || this._writableState.ended)
+ return;
+
+ // just in case the user is about to call write() again.
+ this.write = function() {
+ return false;
+ };
+
+ // no more data can be written.
+ this.end();
+}
View
@@ -13,22 +13,12 @@
module.exports = Transform;
-var Readable = require('./readable.js');
-var Writable = require('./writable.js');
-
+var Duplex = require('./duplex.js');
var util = require('util');
-
-util.inherits(Transform, Readable);
-
-// parasitic inheritance.
-Object.keys(Writable.prototype).forEach(function(method) {
- if (!Transform.prototype[method])
- Transform.prototype[method] = Writable.prototype[method];
-});
+util.inherits(Transform, Duplex);
function Transform(options) {
- Readable.call(this, options);
- Writable.call(this, options);
+ Duplex.call(this, options);
// bind output so that it can be passed around as a regular function.
this._output = this._output.bind(this);

0 comments on commit 9a0662b

Please sign in to comment.