読者です 読者をやめる 読者になる 読者になる

TwitterStreamをTatsumakiを使ってブラウザ表示

twitter perl PSGI/Plack Tatsumaki

http://d.hatena.ne.jp/memememomo/20100408/1270679837
こちらのプログラムの結果をTatsumakiを使用してブラウザで表示するようにしました。

app.psgi


ここでは、ディスパッチ設定を行ないます。
http://localhost:5000/{トラックワード}」でアクセスしてきた時の設定と
http://localhost:5000/{トラックワード}/poll/」でアクセスしてきた時の設定を行ないます。
後者はjavascriptのイベントループ内でアクセスされます。

package main;
use Tatsumaki::Application;
use File::Basename;

my $word = '[\w\.\-]+';
my $app = Tatsumaki::Application->new([
   "/($word)/poll/"  => 'TweetHandler',
   "/($word)"             => 'HtmlHandler',
]);

$app->template_path( dirname(__FILE__) . "/template" );
$app->static_path( dirname(__FILE__) . "/static" );

return $app;


my $app = Tatsumaki::Application->new([ ... ]);
の部分で、どのアクセスにどのモジュールを使用するかを設定しています。

HtmlHandler


http://localhost:5000/{トラックワード}」でアクセスしてきた時の処理を書きます。

package HtmlHandler;
use Moose;

extends 'Tatsumaki::Handler';

sub get {
    my $self = shift;
    my ( $track ) = @_;
    $self->render( 'index.html' );
}

no Moose;


ツイートを表示するページを表示します。
テンプレートは下記のようなもの。

% my $track = $_[0]->{handler}->args->[0];
<html>
<head>
<title> Track Word 「<%= $track %></title>
<script type="text/javascript" src="static/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="static/jquery.ev.js"></script>
<script type="text/javascript">
jQuery( function ($) {
   $.ev.loop('/' + <%= $track %>' + '/poll/' + '?session=' + Math.random(), {
      tweet : function(ev) {
          if(! ev.tweet.user || ! ev.tweet.text) return;
          $( "#tweets" ).prepend(
             ev.tweet.user.screen_name + ": " + 
             ev.tweet.text + "<br>"
          );
       },
      message : function(ev) {
          $( "#tweets" ).prepend(
             '<span style="color: #f00;">' + ev.text + "</span><br>"
           );
       }
    });
});
</script>
</head>

<body>

<h1>Track Word 「<%= $track %></h1>
<div id="tweets"></div>

</body>
</html>


ツイートを表示する領域を準備します。
また、javascriptでイベントループを回して、サーバ側にアクセスします。


TweetHandler


javascriptからのアクセスに対して、処理します。
リクエストを受け取ると、AnyEventでのイベントループが周り始めます。

package TweetHandler;
use Moose;
use Config::Pit;
use AnyEvent::Twitter::Stream;
use Tatsumaki::MessageQueue;
use Tatsumaki::Error;

extends 'Tatsumaki::Handler';
__PACKAGE__->asynchronous(1);

my ($username, $password) = do {
   @{ Config::Pit::get( 'twitter.com', require => {
      'username' => 'memememomo',
   })}{ qw/username password/ };
};

my %streams;

sub create_stream {
   my $self = shift;
   my ( $track ) = @_;

   my $mq = Tatsumaki::MessageQueue->instance( $track );
   $streams{$track} ||= AnyEvent::Twitter::Stream->new(
      username => $username,
      password => $password,
      method => 'filter',
      track => $track,
      on_tweet => sub {
          my $tweet = shift;
          $mq->publish( { type => 'tweet', tweet => $tweet, } );
      },
      on_error => sub {
          my $error = join ',', @_;
          $mq->publish( { type => 'message', text => $error, } );
          delete $streams{ $track };
      },
      on_eof => sub {
          $mq->publish( { type => 'message', text => 'disconnected', } );
          delete $streams{ $track };
      },
      );
}


sub get {
      my $self = shift;
      my ( $track ) = @_;

      my $session = $self->request->param('session')
          or Tatsumaki::Error::HTTP->throw(500, "'session' needed");
      
      $streams{ $track } or $self->create_stream( $track );
      my $mq = Tatsumaki::MessageQueue->instance( $track );
      $mq->poll_once( $session, sub {
           my @events_published = @_;
           $self->write( \@events_published );
           $self->finish;
      });
}

no Moose;

起動


「plackup app.psgi」で起動して、「http://localhost:5000/perl」でアクセスしてみます。
そうするとツイートに「perl」を含んだものがずらずらと流れるように出力されると思います。