Home > Archives > 2009-10

2009-10

JSocketを使ってPOSTもストリーミングするPlackアプリ

  • 2009-10-20 (火)
  • perl
  • hatena count

さて、前エントリJSocketというのを作ったと書いたのですが、これは実はjavascriptで動くtwitter streamクライアントを作るならばmultipart/mixedを使うべきというのを読んで、レスポンスがpollではなくてストリーミングできるというのを知って、リクエストもやりたいよというふうに思ったのがきっかけでした。

まず、XHRでできないかを試してみたのですが、xhr.send(data)を一回読んでしまうと少なくともjavascript側ではリクエストは完了したと思ってしまって、再度xhr.send(data)しても反応はありませんでした。

そこでJSocketの登場です。JSocketを使うとhttpリクエストを断続的に送信することができます。やったですね。

で、Plack::Server::Coroを使って試しに
リアルタイムチャット
を作ってみました。どうぞお試し下さい。レスポンスもJSocketを使っていますのでmultipartに比べてboundary分お得だったりもします。テキストエリアに入力された文字がストリーミングで送信され、また他人のデータもストリーミングで受信できていると思います。ちなみに自分の発言もサーバから持ってきてるので一人でも確認できます。

ちなみにこれを1つのコネクションでやってしまおうというのがWebsocketなんだろうという認識ですね。ただwebsocketはhttpの上に一応のってますがハンドシェイク以外の部分はhttp/1.0やhttp/1.1的には正しくないでしょうし、JSocketでの二重接続であれば正しいhttpとしてふるまえるはずで、現行のapacheやproxy等でも扱える可能性があったりします。

あ、チャットのサンプルコードもgithubにあげてあります。

plackup -s Coro --app chat.psgi

という感じでPlack::Server::Coroをお使いください。

javascriptからsocketが扱えるJSocketを作りました

javascriptからsocketを扱いたいなぁという事象が発生したんですが(それについては別エントリで)、SocketJSというのがあるんですがDownloadするところがなぜかSSLになっていてCAがCAcertでfirefoxだとデフォルトでは見れないので、かっとなって自分で作ってみました。今も反省していません。

コードはgithubからどうぞ。
使い方はjs/jsocket.jsに軽く書いてあります。

/*
 * Jsocket - Socket on Javascript
 * Author: Masahiro Chiba <nihen@megabbs.com>
 * Depends:
 *  - jQuery: http://jquery.com/
 *  - jQuery TOOLS - Flashembed: http://flowplayer.org/tools/flashembed.html
 * SYNOPSIS:
 *  JSocket.init('/static/JSocket.swf', function () {
 *     socket = new JSocket({
 *         connectHandler: connectHandler,
 *         dataHandler:    dataHandler,
 *         closeHandler:   closeHandler,
 *         errorHandler:   errorHandler
 *     });
 *     socket.connect(location.hostname, location.port || 80);
 *  });
 *  function connectHandler() {
 *      socket.write("GET / HTTP/1.0\x0D\x0A\x0D\x0A");
 *      socket.flush();
 *  }
 *  function dataHandler(data) {
 *      alert(data);
 *      socket.close();
 *  }
 *  function closeHandler() {
 *      alert('lost connection')
 *  }
 *  function errorHandler(errorstr) {
 *      alert(errorstr);
 *  }
 *
 * */

こんな感じですね。flashの力を借りているので、Flashのソケットポリシーファイルとかを参考にポリシーファイルを配布するサーバを立ち上げておいてから使ってください。まる。

mod_psgi試してみた

  • 2009-10-16 (金)
  • perl
  • hatena count

mod_psgi をインストールしてみたをみて速くなるなら試してみようということでmod_psgiを試してみますた。

まずはこんな感じの簡単なPSGIアプリで。

my $app = sub {
    return ['200', [Content-Length => '5'], ['hello']];
};
ab -n 10000 -c 100
mod_psgi
 Requests per second:    1403.51 [#/sec] (mean)
mod_perl
 Requests per second:    668.33 [#/sec] (mean)
Standalone
 Requests per second:    702.46 [#/sec] (mean)
Standalone::Prefork
 Requests per second:    725.78 [#/sec] (mean)

おおおお。超絶早いですね!
(plackupの際に-E product(development以外ならなんでもおk)をつけないとだいぶ遅くてそれをそのまま載せてたのを修正しました)

で、お次は、Catalyst::Engine::PSGIを使ってCatalystのhello worldなアプリを。

catalyst.pl Hello

で作って、debugモードを切って、Root.pmのindexで

    $c->response->content_type('text/plain');
    $c->response->body( 'hello' );

こんな感じにしたもの。

ab -n 1000 -c 10
mod_psgi
 Requests per second:    207.87 [#/sec] (mean)
mod_perl
 Requests per second:    144.94 [#/sec] (mean)
cat-standalone
 Requests per second:    184.95 [#/sec] (mean)

おおおおお。早いですね!!これはこれだけでも乗り換える意味がありそうだ。と思ってたんですが現在実運用中のCatalystアプリでやってみたところ”child pid 32320 exit signal Segmentation fault (11)”とかいって死にました。うーむ。これは再現する最小構成を探ってid:spiritlooseさんにフィードバックしたいところですね。

casual-perlerな人たちは今持ってるCatalystアプリをmod_psgi+Catalyst::Engine::PSGIで動かしてどんどんフィードバックするといいんじゃないかな!

Archer and Git

  • 2009-10-16 (金)
  • git
  • hatena count

最近会社のレポジトリ管理も順次gitに移行しようとしてるのですが、今までArcher&svnでデプロイしていたものをgit用にarcher.ymlを書き換えしてみた。

汎用的にはこんな感じ。中央サーバのレポジトリにreleaseというブランチを作っておいて、作業者もそれの追跡ローカルブランチなreleaseを作っておくというのが前提。releaseに直接コミットは厳禁。

git stash saveがあるから作業ディレクトリを別に用意する必要ないかなぁとか思ってこんな形にしてみた。今のところ満足してるけど運用しているうちになんか不具合がでるかもしれない。

Acme::Coro::Sukeをリリースしました

  • 2009-10-12 (月)
  • perl
  • hatena count

多分、5人以上の人が思いついたけどあまりのくだらなさに作成を断念したといううわさのAcme::Coro::Sukeを先ほどCPANにリリースしました。(githubにもあげてあります)

これは、Coroのasyncと基本的には同じ動作をするbenzoというブロック定義ができるようになるもので、benzoブロックにCoroがスレッドを切り替えるたびに、「うわぁ…べんぞうさんの中…すごくあったかいナリぃ… 」とコロちゃんが囁やいてくれるモジュールです。
一番簡単な使い方は以下のようになります。

use Coro;
use Acme::Coro::Suke;
benzo {
};
cede;

enjoy Acme::Coro::Suke!

CPANに上げる三つめのモジュールがAcmeモジュールというのはこれはひどい。

Re: PSGI Implのsendfileについて

  • 2009-10-07 (水)
  • perl
  • hatena count

PSGI Implのsendfileについてですが、自分の今のところのイメージを書いておくです。

on Plack::Server

  • $res->[2]がGLOBだったら fileno($res->[2])して sendfile に fd を渡す
  • $res->[2]->can(‘fileno’) が生えてたら、$res->[2]->filenoからfdを取って使う
  • $res->[2]->can(‘path’) が生えてたら、$res->[2]->pathからファイルパスを取って使う

$env->{psgix.sendfile}を使わない以外は一緒

on app

realfileをserveしたい時は

  • GLOBを返す
  • ->pathを生やしたIO-Handle-likeなオブジェクトを返す

の二種類の方法があって、後者のほうがあらゆるサーバで最適化される可能性がある。かといって前者だからといってクライアントに届くresponseが変わることはないと期待される。後者において->filenoの実体のファイルと->pathが違うものだった場合の動作は未定義。

on middleware

  • Plack::Middleware::XSendfile
    responseから->pathが取れる場合にはそれをヘッダのX-Sendfileにセットするようなmiddleware。これのpsgix.sendfileサポートを無くしたやつのイメージ。
    X-Sendfileヘッダをセットする場合というのはbackendがlightyの場合とかだと思うけど、それをセットしていいかどうかはPlackは知り得ない。かといってappでセットしていて必要のない時に外にファイルPATHが出ていくものいくない。というわけでappでは->path付きオブジェクトを返すだけにして、このmiddlewareをbackendにあわせて付けたり外したりする。Plack::Server::*のsendfile(2)サポートとかとはまったく関係無い。
  • Plack::Middleware::GuessPath
    GLOBからファイルPathを推測して->path付きのオブジェクトに変換しちゃうMiddleware。マルチプラットフォーム対応が課題。Plack::Middleware::XSendfileより先に実行する。Plack::Server::*のsendfile(2)サポートとも関係する。


追記(10/7 17:24): 大体ここに書いてある感じで追加されたみたいです。詳しくは本家specのchangesetをご覧ください。Plack::Middleware::XSendfileも追加されたみたいです。miyagawaさん仕事ハヤス、、、。

ファイルPATHを覚えているfhを作成できるIO::File::WithPathをリリース

  • 2009-10-07 (水)
  • perl
  • hatena count

Plackのsendfileサポート関連を追いかけてて、Plack::Server::Apache2でsendfileサポートされてない理由がfhからファイル名を取るベストな方法がないというわけで、gist: 200797みたいなパッチを書いて#http-engineとかに張り付けたけどそれlinuxでしか動かないよねみたいなことで日本の恥を晒してしまったりしてたわけですが、その中でIO::File::WithPathみたいなのがあればいいよねと話がでていたので作ってみました。

CPANgithubにあげてあります。

使い方はこんな感じ。

    my $fh = IO::File::WithPath->new('/path/to/file');
    print $fh->path; # /path/to/fileがとれるよ
    print $fh->getline; # IO::Handleとしても扱える
    print <$fh>; # もちろんGLOBとしても

Plackのappでは

    return ['200', [], IO::File::WithPath->new('/path/to/file')];

みたいな使い方を想定していますが、Plack::Server側はこのモジュールを使うことが前提というわけではなくて、duck typingで->pathがあるオブジェクトであればそのpathを(使える条件であれば)使うようになる予定だと思います。

あと、純粋なfhからpathを取るマルチプラットフォーム対応なモジュールもできれば欲しいよねというところ。windowsはかなり無理っぽい。

Home > Archives > 2009-10

Search
Feeds
Meta

Return to page top