Introducing NDNts, Named Data Networking libraries for the Modern Web
I'm creating a new Named Data Networking (NDN) client library, NDNts.
The initial NPM release,
v0.0.20191223-beta.1, was uploaded yesterday.
This article explains why I'm doing this, and why you should consider using my library.
I've been developing Named Data Networking (NDN) for several years. Although my specialty is in the forwarding plane, I occasionally build NDN applications, such as a home surveillance camera. A common ingredient of every NDN application is some sort of client libraries, which provides APIs that allow the application to encode/decode NDN packets and communicate over NDN networks in accordance with the NDN protocol. One of these client libraries is the NDN Common Client Libraries (NDN-CCL), which provide a consistent API across several programming languages.
- Callbacks everywhere, leading to callback hell.
- The library inserts over 50 symbols to the browser's global scope, causing name conflicts.
- All features are bundled into a single file that weighs over 500KB.
- There's no unit testing for the most part, let alone continuous integration.
I made several attempts to improve the situation.
For example, I published
@types/ndn-js package, enabling using ndn-js in TypeScript projects.
However, being constrained by ndn-js's stated goals (especially, inter-language API), what I could do is limited.
In 05 Sep 2019, owner of NDN-CCL announced that they are no longer maintaining the project because their funding has run out:
REMAP has no current support to update the CCL and CNL libraries. We do not intend to abandon either library, but have no funding to do work on them, either.
It's time for The Big Rewrite ™.
I started working on NDNts shortly after REMAP's announcement.
I decided early on that I should write the library in TypeScript.
I encountered TypeScript at a workshop in 2016, used it several times, and then it became my most loved programming language.
Writing the library in TypeScript enables compile-time type checking, which greatly reduces the chance of making mistakes regarding variable types.
The name of this project,
NDNts, reflects this design decision.
Like most of my other projects, I don't care much about backwards compatibility. The beauty of NPM is that, all published versions are available forever, and you can pick any version in your dependencies. Being a personal project, I have to prioritize in developing for the latest and greatest, instead of worrying about backwards compatibility.
NDNts will be a set of libraries, not a single library. This enables application developers to only pick the features they need, and matches the practice of most projects on NPM today. A drawback is that web applications have to use a module bundler, but this could change in the future when I figure out how to offer standalone bundles of common feature sets.
Test coverage is important. So far I have included unit testing coverage for all library components, except command line interfaces. I even have browser tests that are executed automatically as part of continuous integration.
The initial release of NDNts consists of 22 packages. Each package has a README that describes what's in that package and often contains code samples, but I'd give a big picture here.
We start from packet representation and encoding:
@ndn/tlvimplements Type-Length-Value structure encoder and decoder.
@ndn/packetdefines basic packet types including Interest and Data, as well the all important Name.
Now we have packets, we can send and receive them via Transport types:
@ndn/node-transportimplement transports for Node.
@ndn/ws-transportimplements a WebSockets transport that works in both Node and browser.
- Each transport has a pair of async iterables for RX and TX, which receives and transmits TLV elements.
I chose async iterables over Node Streams, because it's just as powerful in processing infinite streams, while avoids a heavy dependency on
@ndn/l3facewraps a transport into a network layer face, which offers async iterables of Interest/Data packets.
With the ability of sending and receiving packets, we can get to the core:
@ndn/fwimplements the forwarding plane.
- The README of that package explains why we need a forwarding plane in the application.
- Yes, I learned this from NDN-Lite.
If you are writing applications, you'll probably start here:
@ndn/endpointimplements Endpoint type, which allows you to express an Interest, or become a producer under a name prefix. This is usually called "face" in other libraries, but we have so much more, so that I think it deserves a different name.
@ndn/keychainprovides crypto features.
Going a little higher layer:
@ndn/segmented-objecthelps with a common use case of segmenting a large object into right-sized Data packets.
@ndn/autoconfigestablishes connectivity to the global NDN testbed.
@ndn/nfdmgmtallows prefix registration on the NDN Forwarding Daemon (NFD). Currently prefix registration (some of them in
@ndn/fw) lacks error recovery; this will be improved in the future.
Finally, there are several command line tools that serve as examples of how APIs can be used in Node:
netcatfor NDN. It demonstrates how to use
@ndn/segmented-objectto transfer a file.
@ndn/keychain-cliis a command line utility to access the
@ndn/keychain. Apart from basic features, it can import keys from ndn-cxx KeyChain, or request certificates from NDNCERT Certificate Authority.
The best, however, is the
It distills the essence of NDN into one emoji.
I'm not going to explain, and you just have to see it yourself.
Then, install relevant NDNts packages via NPM, and you can start coding.
Thanks and good luck!