Most CCN applications I’ve seen or written so far go something like this:
This is a fairly common pattern so I decided to write a little framework to help hide the mundane details that go into structuring these applications. The result – protoccn – is a Flask-like  framework for creating producer and consumer CCN applications. In this post I’ll outline some basic examples of the framework to build a simple file server.
Producers in CCN applications can be differentiated by how they respond to interests with a specific name. The rest of the mechanics – listening for incoming interests, extracting the name and payload information to act on it, and invoking a particular callback – are common among many applications. Consider the following code snippet taken from the PARC standard file transfer application written in C.
The code should be quite readable. The meat of this infinite loop is a call to
_createInterestResponse. This function generates a content
object response for the incoming interest.
Even though this loop is simple, it would be nice to hide it from the application developer. That’s what protoccn does. Here’s the producer code that provides this functionality.
The Producer class has two methods:
method is a decorator that takes a string and some other options. The string is an
interest name prefix. This decorator has the effect of registering the decorated
function as a callback whenever an interest with the specified prefix arrives at
the producer. The
run function implements the infinite loop to listen for
interests and invoke the specified callback. The payload of the content object
response is then set to the output of the callback. Pretty simple.
The goal of the consumer part of the protoccn framework is to allow application developers to configure functions or methods that can trigger interests and return their responses. It provides two ways of doing this:
A consumer can register a custom function or method which maps to an
interest request. For example, an application can create a method called
get_data that, when invoked, issues an interest for, say, “ccnx:/random/data,”
and returns the response.
A consumer can create a function “sink” that points to a data location
and serves to generate the payload of the interests sent to that location. For
example, one could define a method called
send_data to accept a string
parameter. A sink can that refers to the location to where the data is sent
can decorate this method. Upon invoking the
send_data method, the
string parameter is inserted into the interest payload and then sent in
an interest carrying the locator name.
The following gist summarizes the main parts of this simple consumer framework.
Now that I’ve discussed the basics of the
it’s now time to build the simple file server. It will work as follows:
Consumers will download files by issuing interests for them. The interest name will
contain some routable prefix that identifies the server, a string command to indicate
what should be done with the request, and the remainder of the suffix carries the
parameter of said command, e.g., the file to download. We will only support two commands:
Producers will listen for interests and respond to them with the respective content. A list request will generate a recursive listing of the directory rooted at the server’s “mount point.” A fetch request will generate the content of the indicated file. In both cases, the producer returns the result to the consumer in the payload of a content object.
Let’s start with the
The code should be pretty simple to read. The producer registers two methods to
list commands separately. The contents of those
methods are also pretty simple to understand:
fetch reads the specified
file and returns the payload whereas
list generates the contents of the
server directory as a list.
The consumer code is almost just as simple. It’s shown below.
Consider the nature of the
fetch commands. The
doesn’t take any parameters, so we it’s registered as a method in the application
register function. Conversely, the
fetch command does require
an argument. As mentioned above, it inserts the name of the file to
fetch as the suffix of the interest name. Therefore, we use the
decorator to create a function that, when invoked with a file name, appends
that file name to the suffix of the locator.
A sample run of the consumer is below.
list command shows that there are four files to be downloaded. The
fetch command then retrieves and prints the file contents to stdout.
And that’s it. I’ll try to write more applications using this framework. But even if I don’t, it was still fun to put together and play with the API.