Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to code two-way duplex streams in NodeJS

In the latest few versions of NodeJS (v0.10.X as of writing), the Streams API has undergone a welcome redesign and I would like to start using it now.

I want to wrap both the input and output of a socket with an object which implements a protocol.

The so-called Duplex interface, seems to just be any stream which is readable and writable (like a socket).

It is not clear whether Duplexes should be like A or B, or whether it doesn't matter.

   +---+        +---+
-->| A |-->     |   |-->
   +---+        | B |
                |   |<--
                +---+

What is the correct code-structure/interface for an object which has two writeables and two readables?

+--------+   +----------+   +----
|       r|-->|w        r|-->|w    
| socket |   | protocol |   | rest of app
|       w|<--|r        w|<--|r    
+--------+   +----------+   +----

The problem with the diagram above is that the protocol object needs two separate read methods and two write methods.

Off the top of my head, I could make the protocol produce 'left' and 'right' duplex objects, or 'in' and 'out' duplex objects (to slice it a different way).

Are either of these the preferred way, or is there a better solution?

like image 236
fadedbee Avatar asked Oct 16 '13 11:10

fadedbee


People also ask

Is duplex a Node.js stream?

Duplex streams are a fundamental category of streams in Node. js. However, they're often misunderstood, including the Duplex stream. This type of stream is hybrid, meaning it expects a read and write method while it's implemented.

How do you switch between modes in readable stream mode?

All readable streams start in the paused mode by default. One of the ways of switching the mode of a stream to flowing is to attach a 'data' event listener. A way to switch the readable stream to a flowing mode manually is to call the stream. resume method.


2 Answers

          |      app      |
          +---------------+
              ^       |
              |       V      
           +-----+ +-----+
           |     | |     |
+----------|     |-|     |-+
| protocol | .up | |.down| |
+----------|     |-|     |-+
           |     | |     |
           +-----+ +-----+
              ^       |
              |       V
          +---------------+
          |     socket    |

My solution was to make a Protocol class, which created an Up Transform and a Down Transform.

The Protocol constructor passes a reference (to itself) when constructing the Up and Down transforms. The _transform method in each of the up and down transforms can then call push on itself, on the other Transform, or both as required. Common state can be kept in the Protocol object.

like image 168
fadedbee Avatar answered Oct 15 '22 00:10

fadedbee


A duplex stream is like your diagram B, at least for the user. A more complete view of a stream would be to include producer(source) with the consumer(user). See my previous answer. Try not to think both read/write from a consumer point of view.

What you are doing is building a thin layer over the socket for protocol, so your design is correct :

                         -------+     +----------+     +------
                               r|---->|         r|---->|      
                         socket |     | protocol |     | rest of app
                               w|<----|         w|<----|      
                         -------+     +----------+     +------

You can use duplex or transform for the protocol part.

                 +---------+--------+---------+       +------------------+ 
                 | _write->|        |         |r      |   Transform  ->  |r
                 |-----------Duplex-----------|       +------------------+    
                 |         |        | <-_read |w      |   <- Transform   |w
                 +---------+--------+---------+       +------------------+

process being your protocol related processing on incoming/outgoing data using internal _read, _write. Or you can transform streams. You would pipe protocol to socket and socket to protocol .

like image 27
user568109 Avatar answered Oct 15 '22 01:10

user568109