A simple chat server in AnyEvent
Node.js でつくってるやつ をみて同じくらいで書けそうだなと思ったので試しに AnyEvent で書き直してみた。
#!/usr/bin/perl
use strict;
use warnings;
use AnyEvent::Socket;
use AnyEvent::Handle;
my @clients;
tcp_server undef, 7000, sub {
my ($fh) = @_ or die $!;
my $h = AnyEvent::Handle->new( fh => $fh );
my $leave = sub {
my $client = delete $clients[ fileno($fh) ];
for my $c (grep { defined } @clients) {
$c->{handle}->push_write("$client->{name} has left.\n");
}
};
$h->on_read(sub {
shift->push_read( line => sub {
my ($h, $line) = @_;
my $client = $clients[ fileno($fh) ];
unless (defined $client->{name}) {
if ($line =~ /(\S+)/) {
$client->{name} = $1;
$h->push_write("===========\n");
for my $client (grep { defined } @clients) {
next if $client->{handle} eq $h;
$client->{handle}
->push_write( "$client->{name} has joined.\n" );
}
}
return;
}
my ($command) = $line =~ m!^/(.+)!;
if ($command) {
if ($command eq 'users') {
$h->push_write("- $_->{name}\n") for grep { defined } @clients;
}
elsif ($command eq 'quit') {
$leave->();
}
return;
}
for my $c (grep { defined } @clients) {
next if $c->{handle} eq $h;
$c->{handle}->push_write( "$client->{name}: $line\n" );
}
});
});
$h->on_error(sub {
my ($h, $fatal, $msg) = @_;
$leave->();
$h->destroy;
});
$clients[ fileno($fh) ] = {
name => undef,
handle => $h,
};
$h->push_write("Welcome, enter your username:\n");
};
AE::cv->wait;
行数的にはほぼ同じくらい。
追記@2009-12-08T10:36:37+09:00: left なメッセージがおかしかったので直した。
AnyEventでirssiプラグインを書く
AnyEvent はその名の通りさまざまなイベントインタフェースに対応していて、その中に irssi が使用している Glib も含まれているため、irssiのプラグインの中で普通に AnyEvent を使用することができます。
キーワード反応を im.kayac.com で自分の IM に通知する higlith2im.pl プラグインを AnyEvent を使用するように書き換えたのが以下です。
use strict;
use warnings;
use Glib;
use Irssi;
use AnyEvent::HTTP;
use HTTP::Request::Common;
our $VERSION = '0.1';
our %IRSSI = (
name => 'hilight2im',
description => 'notify hilight message to IM via im.kayac.com api',
authors => 'Daisuke Murase',
);
sub sig_printtext {
my ($dest, $text, $stripped) = @_;
if ( $dest->{level} & MSGLEVEL_HILIGHT ) {
my $user = Irssi::settings_get_str('im_kayac_com_username') or return;
my $msg = sprintf('[irssi] %s', $stripped);
my $req = POST "http://im.kayac.com/api/post/$user", [ message => $msg ];
my %headers = map { $_ => $req->header($_), } $req->headers->header_field_names;
my $r;
$r = http_post $req->uri, $req->content, headers => \%headers, sub { undef $r };
}
}
Irssi::signal_add('print text' => \&sig_printtext);
Irssi::settings_add_str('im_kayac_com', 'im_kayac_com_username', '');
fork する必要がなくなってシンプルですね!
...とおもいきや現状の AnyEvent::HTTP はなんと HTTP::Request オブジェクトからのリクエスト送信に対応していないため、自分ですべてのリクエストを組み立てる必要があるようです。これは不便。。
ですが、irssi の中で普通に AnyEvent を使うことができるのはなかなか便利です。お試しあれ!
AnyEvent 版は github にあげた。
AnyEventの良いところを3行で
教えて!と言われたのでそのとき答えた物をここにも記す。
- POE みたいにきもくない
- Danga::Socket とかだと自分で実装しないといけないread queueとかそういうのも面倒見てくれる便利モジュールがある>AnyEvent::Handle
- ドキュメントがアツイ
最後のは主に AnyEvent::Intro のことを言ってますが、これ一通り読めばとりあえず AnyEvent 使えるようになるっていうくらい完璧な内容となっています。
AnyEventとは何かからはじまり、非同期プログラミングの説明からAnyEventを使用したシンプルな例が続き、AnyEvent::Socket や AnyEvent::Handle を使用するのを順々に詳しく説明してくれています。 どうして AnyEvent::Handle みたいな物を使うといいのかというところまで書かれているので、非同期プログラミングやネットワークプログラミングにあまり詳しくない人でも読めるのではないでしょうか。
AnyEvent で $poe_kernel->alias_set 的なことをする方法
最近 AnyEvent にはまっています。おもしろい!
AnyEvent と同じ非同期プログラミングフレームワークであるところの POE では
$kernel->alias_set('hoge');
などとしておくと
$kernel->post( hoge => 'state' );
みたいな感じでどこからでもそのコンポーネントを呼び出すことができました。 しかし AnyEvent ではそう言った機能がないため以下のように Object::Container を使って解決することにしました。
呼び出される側:
use AnyEvent;
use Object::Container 'event';
my $cv = AnyEvent->condvar;
$cv->cb(sub {
my (@args) = $cv->recv;
# ここになんか処理
});
event->register( foo => sub { $cv } );
呼び出す側:
use AnyEvent;
use Object::Container 'event';
event('foo')->send(@args);
Condvarをグローバルなシングルトンコンテナに入れ、それを使って相互にやりとりをするという感じですね。
Object::Container は export する機能がなかったのですが、毎回 Object::Container->get(...)
などとかくのがだるかったので import に引数渡すとその名前でコンテナを export する機能をつけました。(0.2以降)
同等のことはいろいろな方法があると思いますが、これが一応今の所の僕の解となってます。参考までに!
Text::MicroTemplate を拡張してみた
最近は Text::MicroTemplate (TMT) をよく利用するようになったのですが、使用するにつれ不満なところが出てきたのでそれを解決するために少し拡張してみました。
実際には拡張したのは Text::MicroTemplate ではなく、Text::MicroTemplate::File です。
http://github.com/typester/text-microtemplate-extended-perl/tree/master
現在二つの機能を追加してあるのでそれを以下にまとめておきます。
テンプレートの継承機能を追加
テンプレートを分割するような規模になってくると現状の TMT では
<?=r $self->render_file('header.mt') ?>
ここにコンテンツ
<?=r $self->render_file('footer.mt') ?>
などのように書くことになりますが、これは TT の wrapper 機能などに慣れていると少しめんどくさい。
追記: TMTでもwrapperはつかえるみたいです。> $mtf->wrapper_fileそこで、TMT でも wrapper 機能をつかえるように!! ・・・しようかと思ったのですがやめて、代わりに Django のテンプレートなどで採用されている継承という仕組みを実装してみました。
詳しい説明は Django のテンプレートのドキュメントがとても詳しいのでそちらを参照するといいと思います。
で、上記の Django ドキュメントにあるテンプレート継承の例をこの拡張版 TMT で書くとどうなるかというと、base.html (base.mt) が
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<link rel="stylesheet" href="style.css" />
<title><? block title => sub { ?>My amazing site<? } ?></title>
</head>
<body>
<div id="sidebar">
<? block sidebar => sub { ?>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/blog/">Blog</a></li>
</ul>
<? } ?>
</div>
<div id="content">
<? block content => sub {} ?>
</div>
</body>
</html>
child.html (child.mt) は:
text
のようになります。
TT のような wrapper という方式と、このような継承という仕組みはどちらも一長一短ありますが、柔軟にテンプレートを定義できるのは継承の方かなぁと感じてます。
ちなみに Django テンプレートに実装されている block.super
相当の機能はまだ実装できていません。
テンプレートに名前付き引数を渡せる機能を追加
もう一つ、テンプレートに名前付きで値を渡せる機能も追加しました。オブジェクトを作成するときに
Text::MicroTemplate::Extended->new( include_path => ['.'], template_args => { foo => 'bar' } );
などのように template_args パラメータにハッシュリファレンスを渡しておくと、テンプレート中でこのハッシュのキーを
<?= $foo ?> # => bar
と参照することができるようになるという機能です。
カヤックxクックパッド主催 技術者交流会で発表してきた
これ
オーディエンス的にperlの話よりいいと思ったので、もっと概念的な、もっといろいろオープンにしてこうぜ!っていう話をしました。
スライドはこちら
以下感想
ElectricCafe.js 村式 中川さん
js でポリゴン。写真を元にポリゴン化。すごい!
村式と言えば鎌倉小町通り沿いにオフィスを構えたご近所さん。こんなところにこんな変態がいたとは!!(褒め言葉)
また遊びに行かせてください!
イケメンCTOの画像検索、全然出ないし!!! だまされた!
誰かが質問してたけど、特徴点をjsだけで自動で出せたら面白いなー。
プログラミングの【さしすせそ】 kwappa.net 塩谷さん
- 料理
- つくる -> たべる -> おいしい!
- プログラミング
- つくる -> うごかす -> たのしい!
どっちも楽しい。幸せを作る作業 だといっていた。いい言葉ダナー;;
さて、どちらもやはり基礎が大事だよね!
- 料理
- さしすせそ
- プログラミング
- コンピューターサイエンス
というわけで、基礎を勉強するコミュニティをつくったらしい。おわり。えー!
詳細はこちら
Railsメールウェア Cookpad インターン中村さん
Cookpadに「つくれぽ」という機能がある。
レシピを公開してる人に対し、つくってみたよー、とかおいしかったよー、とかいうのを送れる機能らしい(たぶん)。ネーミングセンスいいなー。
で、それを携帯で送れたらいいよね!っていうことになり、インターンの中村さんががんばったよっというお話。
Javaの James を参考に Ruby で同じような物を実装したとのこと。すごいなー。
perl だと qpsmtpd とかみたいなイメージかな。個人的には最近は qpsmtpd で受信してジョブキューにつっこんであとはゆっくりそっちで処理。というパターンをよく使うな。
皮肉なことに James をホストしてる apache.org のメールサーバーは qpsmtpd だったりするのよねー。
というわけで歓談タイムにqpsmtpdをプッシュしまくっておいた。
あと作ったものを公開はしないんですか? と聞いたところ stable になったら公開したい! とのことなので期待。
カヤックxクックパッド イケメンCTO二人 + 技評 馮さんのトークセッション
クックパッド、何をするかを決めるときに何がベストかをすごい慎重に決める。何かをやるための時間を決めたらその 1/3 は計画に使う。
そして驚いたのは、その計画は全員が納得するまでやるといっていたところ。気持ち悪くなると言っていた。
そして計画で決めるのは仕様ではなく指標。ロジックとなる部分。
完璧なロジックには反対できない。
しかしそれでも会議の結論に対して全員が納得できるというのは相当なことだなーと思って、そのためにどういう手法をとっているのか質問した。
3つあるという答え
- 会議の前に共有された3つの前提条件がある
- この3つがそろったものしかやらない
- EOGS (Emotion Oriented Goal Setting)
- ユーザーの欲求をもとにしてゴールを設定するための指標シート
- ロジックツリー (マインドマップ)
- 前述の通り決めるのはロジック
質問したくせに、3つの前提条件の内容を失念してしまったのでググったところ、 ryo_katsuma さんのナイスな記事がひっかかった。
Ruby on Rails セミナーに参加してきました - blog.katsuma.tv
- Bestなことを見つけるまでのの3つの輪
- やりたい(情熱を持ってとりくめること)
- できる(世界で1番になれること)
- やるべきこと(儲かること)
ってことかな?
やっぱり会議前から前提条件をしっかりそろえて会議のコンテキストをそろえること、会議中も正しくゴールに近づけるようなシステムがある。
広げるだけ広げて、収束しない会議ってよくあると思うんだけど、そういう人たちは参考にするといいと思った。僕もここはもう少し掘り下げてみたい。
あと、イベント終了後にすこしお話しさせてもらったときに、「数値化して比較する」っていうことも最近はやってるとおっしゃっていた。どっちの方法が良いのか迷ったときに、効果や費用などすべてを数値化することで客観的に判断できる。なるほど。
まとめ
料理とプログラミングは似ている。
cookpad 面白い会社。
Mouse なクラスと subtype
今日 Mouse を最新版にしたら書いていたコードが動かなくなった。
subtype していたところで、
The type constraint 'Ark::Request' has already been created in Mouse::Util::TypeConstraints and cannot be created again in Ark::Context
というエラーになってしまう。これは Mouse の subtype のところのコードを読めばすぐわかるが、違う場所で重複定義しようとしたときに出るエラーだ。
subtype 一回しか書いてないのに重複定義とは何事か、と思ったが、今の Mouse では Mouse でクラスを作るとそのクラスに class_type
が設定されるようになってるみたい。
つまりこの場合は Ark::Request
は Mouse なクラスなのですでに class_type
されているのだが、それをさらに subtype で定義しようとしてエラーになってたというわけ。
こちらの挙動が Moose と同じで、いままでの Mouse のほうがちょっと互換性がなかったということみたい。
というようなことを Mouse メンテナーであるところの tokuhirom 氏や、MouseX ファウンダーであるところの ikasam_a 氏に教えてもらった。ありがとうございます!
あわせて読みたい:
Yokohama.pm Tech Talk #4 行ってきた
もう4回目か。。
qudo x skinny (id:nekokak)
qudo
はクドーと読む。キュードーだと思ってた!(& キュードーのが良いなぁ)
Skinny は前回(?)も発表したORM。SQL::Parser
がしょぼい&遅いので捨て、ルールベースにしたとのこと。
それはいいんだけど、DSL まくっててちょっと個人的にはやだなぁ。DSL は覚えるのが大変。DSLは ::Declare
とかで別途やって欲しい感じ。どちらでも使えるのがいいと思います!
現状は一部足りないところもあるけど、だいたいのところ(id:nekokakさんが普段使う領域)はうごくレベルらしい。
Qudo は TheSchwartz みたいなジョブキュー。TheSchwartz の不満なところを直して、欲しかった物をつけた感じの物。
- ORM に依存しない
- DB 以外にも memcached とかキャッシュサーバーをバックエンドにも使える(予定)
- 適度なHookポイントをつけてプラッガブル!
- エラー処理管理しやすく (イイネ)
- 管理系コマンドも充実 (イイネ)
- テストモジュールも用意 (イイネ)
というかなり良い感じの物になってるので、TheSchwartz つかってる僕としては触ってみたいなと思った。ORM 対応とかは正直 DBI にさえ対応してくれればいいんだけど。。
ZIGOROu さんがMacBookになってる!!
DI x Perl! (id:lestrrat)
DIよくわかってない。
オブジェクトの自動組み立てのことをいうらしい = 依存関係を満たしつつ初期化。
。。。というと?
自分で依存関係を考慮してコーディングしなくていい。なるほど。
どうやるか? 普段どおりのクラス定義 + 依存性定義ファイル + アセンブラ(なんだろこれ、前二つを結びつけて組み立てる物)
Bread::Board の実際のコード例。見てもよくわからん。
lestrrat化後はどうなるか (今後取り込まれる予定のもの)
クラス構造使いやすく。(こっちの例はいい感じ)
- Bread::Board (coreモジュール、いままでのようにDSLではない)
- Bread::Board::Declare (いままでのようなDSLインタフェース)
- MooseX::Bread::Board もつくったよ
lestrrat化したあとのものは僕にとってもわかりやすく、一度試してみたい。依存性を全く考慮することなくコーディングできるなら確かに楽なのかもしれないなぁ。
やってみないとわからないので、これは取り込まれたら使ってみる。
WAF のつくりかた (id:dann)
おなかすいた。
いろんな言語のWAFの特徴。最近Djangoってる僕としてはPythonのWAFについてまったく調べてないんじゃないの!! と思ってしまったw Django 面白い機能いっぱいありますよ。
で、それらをいいとこ取りしたのが Angelos!
フックポイントは大文字! きもい!
デフォルトセットの概念は良い。 Module::Setup のフレーバーで定義。いいね。
amazon の MapReduce エラスティックなんちゃら (id:lopnor)
mapper or reducer スクリプトから CPAN モジュールを使用するための方法。
local::lib して jar でかためて云々すれば普通に使えるらしい。
Simo (id:perlcodesample)
Moose とかみたいなやつ。Mouse が存在しなかったら触ってみたかも。
Moose/Mouse との比較があるとよかったかもなぁ。機能比較はもちろんだけど、速度比較とかも。
機能としては MOP 的なものが全くなさそう(?) なので、Moose/Mouse からの移行はなかなか難しそう。
CAPとBASEとEventually Consistent (id:yohei)
職業にふいたw
赤ラクダ本とかしらない>< MogileFS とか Perlbal とかの brad プロダクトを使ってるらしい。 MogileFS の運用話は聞いてみたかったけど懇親会で話す機会なかったなぁ。
CAP定理! どれもとりたいジレンマ。どれかを妥協せざるを得ない。
Webアプリだとたいていの場合 C (Consistency) を妥協。
その C の中の Eventually Consistent というのについての話。これについては「結果整合性」でググれば一番良いページがいちばんうえにくる! ここ?
BASE とか CAP とか全く知らなかったけど、Eventually Consistent 的な手法というのは Web 開発においてはよくつかわれていて、全然わかる話ではあった。
自分の身近では実際の方法論などばかり話されるばかりで、あういう概念的な話は全く出ないので面白かった。もう少し知りたい。
あわせて読みたい:
LT
MacBookのバッテリー切れてメモがない。
id:IMAKADO の perl-completion.el の説明。早口で perl-completion ユーザーの僕としても難しかった。非ユーザーは理解できなかったかも。
ジョブキューは Qudo で良いよって言う結論。(うろ覚え)
AAFind おもろいw やる男がやるプレゼンは新しい。
まとめ
Django本にサインもらった。うれしい
詰まったFCGIプロセスを見つける方法
package FCGI::ProcManager::Debug; use strict; use warnings; use base qw/FCGI::ProcManager/;
sub pm_manage {
my $res = shift->SUPER::pm_manage(@_);
# manager does not return pm_manage, so below code should run in server only
$0 = 'perl-fcgi (waiting)';
$res;
}
sub pm_pre_dispatch {
$0 = sprintf('perl-fcgi (started %s)', scalar localtime);
shift->SUPER::pm_pre_dispatch(@_);
}
sub pm_post_dispatch {
$0 = 'perl-fcgi (waiting)';
shift->SUPER::pm_pre_dispatch(@_);
}
1;
こんな感じの ProcManager
のサブクラスを作り、これを代わりに使用すると、psコマンドでperlプロセスが詰まってないか確認することができるようになる。
プロセスが待機中の時は
perl-fcgi (waiting)
実行中の場合は
perl-fcgi (started Fri Apr 3 14:39:25 2009)
とスクリプト実行開始時間がでるので、それを元に探せばいい。$ENV{PATH_INFO}
等も表示させるともっと親切かも。
Catalyst のアプリの場合、
./script/myapp_fastcgi.pl -manager FCGI::ProcManager::Debug
等とすると使用するmanagerクラスを変更できるようになってるから、コードを変更せずすぐに導入できる点もグッド。
lleval.el
YappoLogs: danさんのllevalをもっと便利にするラッパー作った
一時はcodepadの1/100くらいの利便性まで下がってしまって心配しましたが、80倍便利になってぼくたちのDan the APIが帰って来ました。
ということで、emacs からたたけるようにしてみました。
先日作成した codepad.el と同じようなインターフェースになっていて、M-x lleval-buffer
でバッファをllevalする、M-x lleval-region
で選択したリージョンを lleval する、となっています。
言語はメジャーモードから自動判別されます。
codepad よりレスポンスがはやくて快適ですね!
Enjoy!