npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

dec0de

v0.2.0

Published

Protocol handler based on generators :stars:

Downloads

58

Readme

dec0de

Protocol buffers handler/parser based on awesome ES6 generators.

WTF? (What's That For?)

The Problem

Handling low-level protocol data (e.g. received via socket or stream) can be tricky b/c data is received in packets.

E.g. assume typical HTTP request line:

GET / HTTP/1.1\r\n

A typical server will have this code to accept requests:

server.on('connection', socket => {
  socket.on('data', data => {
    // handle buffers
  });
});

Each data is a buffer that contains some request fragment. It can contain the entire request line, it can contain only it's fragment (e.g. GET / HTTP), it can contain more than that. It can even be received char-by-char.

In order to handle protocols your server needs to:

  • accumulate buffers
  • maintain internal parsing states (typically, microstates for processing each token)
  • organize state changing and buffer consumption
  • provide a notion for "wait for data"
  • handle protocol expectations and throw errors
server.on('connection', socket => {

  // protocol messages output
  const out = new EventEmitter();

  // we need parser state
  let state = 'expect-http-status-line';

  // we need accumulated buffer for handling data
  // received via multiple 'data' event
  let remaining = Buffer.alloc(0);

  socket.on('data', data => {
    // accumulate buffer
    remaining = Buffer.concat([remaining, data]);
    // handle parser state
    switch (state) {
      case 'expect-http-status-line':
        // see if we have accumulated required data for this state
        const i = remaining.indexOf('\r\n');
        if (i === -1) {
          // we need more data
          return;
        }
        // extract protocol-specific data, emit it
        const line = remaining.slice(0, i);
        out.emit('request-line', line)
        // don't forget to consume stuff from buffer
        remaining = remaining.slice(i);
        // don't forget to enter next state
        state = 'expect-headers';
        // phew, we're done here
        break;
      // now handle more protocol parts (headers, body, etc) :(
    }
  });

});

In other words, there's a whole lot of cross-cutting concerns which can easily make your incoming data handler an awful mix of I/O handling, state maintenance and protocol-specific logic — error prone, unreadable and unmaintainable.

The Solution

Meet dec0de — low-level abstraction for handling buffers and expectations.

Thanks to awesome ES6 generators our previous switch-case-based parser state handler can be written in a single line:

function* decodeHttpRequest() {
  const line = yield buf => buf.indexOf('\r\n');
  // handle next protocol parts (headers, body, etc.)
}

Parsing state is maintained via generated iterators in a natural, readable and reliable manner. Internally, dec0de will also handle memory-efficient buffer accumulation/consumption and generator lifecycle (instantiate, pause and resume). All that's left for you is to implement protocol handling logic.

Here's our previous example:

function* decodeHttpRequest() {
  const line = yield buf => buf.indexOf('\r\n');
  out.emit('request-line', line);
  // handle next protocol parts (headers, body, etc.)
}

server.on('connection', socket => {
  const decoder = new Decoder(decodeHttpRequest);
  socket.on('data', data => decoder.decode(data));
});

Please refer to some tests for more examples.

Usage

npm i --save dec0de