Find file
Fetching contributors…
Cannot retrieve contributors at this time
97 lines (75 sloc) 3.14 KB

Until today, I had a script named "". This script was triggered via cron once every hour, to fetch various feeds from services I use (like github,, ...) and to process the result through a template and dump the result in a HTML file.

Today I was reading Tatsumaki's code and some examples (Social and Subfeedr). Tatsumaki is a "port" tornado (a non blocking server in Python), based on Plack and AnyEvent. I though that using this to replace my old lifestream script would be a good way to test it. Two hours later I have a complete webapp that works (and the code is available here).

The code is really simple: first, I define an handler for my HTTP request. As I have only one things to do (display entries), the handler is really simple:

    package Lifestream::Handler;
    use Moose;
    extends 'Tatsumaki::Handler';

    sub get {
        my $self   = shift;
        my %params = %{$self->request->params};
            {   memes    => $self->application->memes($params{page}),
                services => $self->application->services

For all the get request, 2 methods are called : memes and services. The memes get a list of memes to display on the page. The services get the list of the various services I use (to display them on a sidebar).

Now, as I don't want to have anymore my script in cron, I will let Tatsumaki do the polling. For this, I add a service to my app, which is just a worker.

    package Lifestream::Worker;
    use Moose;
    extends 'Tatsumaki::Service';
    use Tatsumaki::HTTPClient;

    sub start {
        my $self = shift;
        my $t;
        $t = AE::timer 0, 1800, sub {
            scalar $t;

    sub fetch_feeds {
        my ($self, $url) = @_;
            sub {
                #do the fetch and parsing stuff

From now, every 60 minutes, feeds will be checked. Tatsumaki::HTTPClient is a HTTP client based on AnyEvent::HTTP.

Let's write the app now

    package Lifestream;

    use Moose;
    extends "Tatsumaki::Application";

    use Lifestream::Handler;
    use Lifestream::Worker;

    sub app {
        my ($class, %args) = @_;
        my $self = $class->new(['/' => 'Lifestream::Handler',]);
        $self->add_service(Lifestream::Worker->new(config => $self->config));

    sub memes {

    sub services {

The memes and services method called from the handler are defined here. In the app method, I "attch" the "/" path to the handler, and I add the service.

and to launch the app

    my $app = Lifestream->app(config => LoadFile($config));
    require Tatsumaki::Server;
        port => 9999,
        host => 0,

And that's it, I now have a nice webapp, with something like only 200 LOC. I will keep playing with Tatsumaki as I have more ideas (and probably subfeedr too). Thanks to miyagawa for all this code.