NEXT、C3
僕はわりと好きかも。
lighttpd+fastcgiで
fastcgiだけ再起動したい場合に、再起動中にアクセスあるとfastcgiプロセスが上がったあとも500になってしまうことがあるのだけど、みんなどうしてる?
タグクラウドモジュール
いろいろあるけどなんでどれもこれもHTML作っちゃうんだろう。もっとシンプルなのほしい。hashで返してくれればいいよ。
とりあえず WWW::CloudCreator
つかって
$c->stash->{tags} = [
map +{
name => $_->[0],
level => do { $_->[2] =~ /(\d+)pt/ },
link => $c->uri_for('/tag', $_->[0]),
count => $_->[1]
},
grep {ref} $cloud->gencloud
];
こんなことして希望通りのものを作ってみてる。こういうのがほしいのだが。
上記の謎の grep {ref}
はWWW::CloudCreatorがタグが空な場合空配列かえせばいいのになぜか空文字かえしてくるといううんこな実装なのでそれ対策。
mobirc-irssi が実用に耐えうるようになりましたのでお知らせします
この間ちょっと紹介したirssiのプラグインスクリプトとしてmobircをつかうmobirc.plスクリプトですが、実用に耐えうる段階まできましたので再度紹介しておきます。
画面サンプルはこんな感じ。(スクリーンショットが取れるPSPでの画面です)
素のmobircはIRCクライアント機能と、HTTPD機能を両方持ち、tiarraなどのIRCプロクシにつなぐことで使用するものになっていますが、こちらのirssiプラグインではmobircのIRCクライアント機能はirssiプラグインとして実装していますので、irssiさえあれは利用することができます。
イメージ的にはirssiがHTTPDを立てている感じになってます。
またキーワード設定などもirssiのハイライト設定を使用していますので、別途mobirc側でキーワード設定をする必要がないのもちょっとうれしいところです。
実際の使い方(インストールの仕方)としては
mobirc.plをirssiのスクリプトディレクトリ (~/.irssi/scripts) にコピーor symlink
irssi起動時にmobircのlibパスを環境変数に入れとく
PERL5LIB=/path/to/mobirc/lib irssi
とか。同じ意味なら何でも。
irssi起動したらmobirc.plをロードする ( /script load mobirc )
ここで
Can't locate XXX.pm in @INC
とか言われる場合モジュール足りないのでそれいれる。ロードしたら config.yaml 自分用にいじって、そのパスをirssiで設定する
/set mobirc_config_path /path/to/config.yaml
設定完了したら /mobirc start すると HTTPD がたちあがる
mobirc started ってirssiコンソールに出てればOK。httpでつないで確認する。
とかでOK。
ほか機能としては、
/mobirc stop
でhttpd停止。/mobirc stop
->/mobirc start
でyaml読み直してHTTPD再起/set mobirc_auto_start on
しておけば次回から/script load mobirc
するだけでHTTPDたちあがる/script load
するのさえめんどいというひとはスクリプトを~/.irssi/scripts
におくかわりに~/.irssi/scripts/autorun
におけば irssi 起動時に自動起動する
という感じ。irssi使いには必須のスクリプトかと思います!
Enjoy!
mobirc クールすぎる
すばらしすぎる!
ソース見ると、IRCクライアント部分とHTTPD部分わかれてるから、IRCクライアント部分を丸々irssiプラグインで置き換えるのも簡単にできそう。
irssi使うようになってからtiarraみたいなプロクシを使わなくなったので、irssiプラグインだけでkeitairc見たいの作りたかったんだよなー。tokuhirom++
てわけで日本シリーズ見ながら作ってみた。
こんなんで一応動く。
irssiプラグイン内でPOEセッション(POE::Session::Irssi)作って、その中で Mobirc::HTTPD 動かしてる。
動くことは動くけど、設定決め打ちだし、unloadもできないのでプラグイン再起動イコールirssi再起動で、まだ実用には耐えない。
とりあえず動くことはわかったのであとは暇なときにでも。
IRCで呼ばれたらIMで通知するirssiスクリプト
僕は以前からIRCでキーワード反応した時に GNU screen のステータスコードに通知を出すようにしている のだけど、ターミナル見てないときがつかないので、またまた im.kayac.com をつかって、IMに通知する irssi のスクリプトを書いてみた。
http://coderepos.org/share/browser/lang/perl/irssi/scripts/hilight2im.pl
使い方は
/set im_kayac_com_username ユーザー名
で自分のim.kayac.comユーザー名をセットするだけ!
あとはirssiで設定したキーワード(irssiではhilightという)を含んだメッセージを受信するとIMに通知される。
ustreamの録画flvデータのURLを得るスクリプト
Clouder::Blogger: ustreamの録画した動画のflvをダウンロードする方法
これは想像ですが、swf内でhttp://gw.ustream.tv/gateway.phpをPOSTしているのはわかっているので、そこで取得しているのか、もしくはJavaScriptでAjaxをつかってどこかから取得しているのか、といったところだと思いますが、いずれにしてももう少し解析が必要です。
とあるのをみて、gateway.php を調べてみました。
これはFlashのAMFのRPCサーバーで、録画されたものを再生するときには client.watch_video
という関数を呼んでいるようです。
as3で書くと
package {
import flash.display.*;
import flash.net.*;
public class gw extends Sprite {
public function gw() {
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
var cid:String = stage.loaderInfo.parameters["cid"];
if (cid) {
var nc:NetConnection = new NetConnection();
nc.objectEncoding = ObjectEncoding.AMF0;
nc.connect("http://gw.ustream.tv/gateway.php");
nc.call("client.watch_video", new Responder(gatewayHandler), { cid: cid });
}
}
private function gatewayHandler(res:Object):void {
for (var i:String in res) {
log(i+": "+res[i]);
}
}
}
}
こんな感じになります。cid は再生URL http://ustream.tv/recorded/RLdKCmCouWOpkkEznZH4QA
とかの RLdKCmCouWOpkkEznZH4QA
部分です。
これをperlで呼ぶにはどうしたらいいか! ということでがんばってみました。
CPANにこのAPIのサーバー側の実装 (AMF::Perl) があったのでそれを適当に読んだり、実際API呼んでるときのパケットと見比べたりしつつして以下のようにすればできました。
#!/usr/bin/env perl
use strict;
use warnings;
use AMF::Perl;
use LWP::UserAgent;
my $cid = shift || '5Fq8cQp9eHsEEknbQ22OOZniqS2xUiuz';
my $amf = AMF::Perl::Util::Object->new;
$amf->addBody('client.watch_video', '/1', { cid => $cid });
my $outputstream = AMF::Perl::IO::OutputStream->new;
my $serializer = AMF::Perl::IO::Serializer->new($outputstream, 'utf-8');
$serializer->serialize($amf);
my $amfdata = $outputstream->flush;
$amfdata =~ s/\xff\xff\xff\xff/\0\0\0\x31\x0a\0\0\0\x01/;
my $ua = LWP::UserAgent->new;
my $req = HTTP::Request->new( POST => 'http://gw.ustream.tv/gateway.php' );
$req->content( $output );
$req->content_type('application/x-amf');
$req->content_length( length $amfdata );
my $res = $ua->request($req);
my $deserializer = AMF::Perl::IO::Deserializer->new(AMF::Perl::IO::InputStream->new($res->content), 'utf-8');
use YAML;
print Dump $deserializer->getObject->getBodyAt(0)->{value};
これで
---
err_desc: ok
server_id: 9
success: 1
user_id: 32983
video_length: 366.207
video_name: broadcast/35957/1191239239348
video_type: broadcast
とかいう出力がでます。これから
http://flash{server_id}.ustream.tv:18881/{video_name}.flv
というflvのURLが作れます。
perlソースの途中の謎の置換 s/\xff\xff\xff\xff/\0\0\0\x31\x0a\0\0\0\x01/;
してて、これはなにかよくわかってません。ただ実際のパケットと見比べて違う部分置換してみたらいけたという代物です。
あとこれで得られるflvデータの音声部分が謎のcodecで変換できない! だれかこれをmp3とかにする方法ご存知のかたいましたらぜひともお知らせください!
CatalystアプリのスタータースクリプトをCodeReposに
あげた。
もともと使ってるのはpmsetupを改造したので雛形つくるだけだったんだけど、毎回DBとか使うわけでもないので、ついでにそこを選べるように改造した。
ほぼ僕専用ルールにのっとった雛形を作成しますので他の方はまったく使えないと思いますが、参考にはなるかもしれません。
他の方のも見てみたいのでぜひともcodereposで共有しましょう!
あ、Catalyst自分規約カンファレンス、とかおもしろいかもしれない。
HTML::TreeBuilder::XPath + WWW::Mechanize なスクリプトを永続化させようとしてはまった
WWW::Mechanize
でコンテンツとってきて TreeBuilder::XPath
で解析するようなのを今まで単機能スクリプトなどでは便利に使っていたのだけど、それを永続的なプロセスで使おうとしたらメモリ使いまくってとんでもないことになったという話。
まずどんどんメモリが増えていくのでタイミングよく読んでいたjrockwayの記事などを参考に、
perl -MDevel::Leak::Object=GLOBAL_bless
付きでスクリプトを実行してみる。
少しソースをいじってまずはループを一回で止めるようにしたときの出力
Tracked objects by class:
Config 1
DBI 1
DBI::var 5
DBIx::Class::ResultSource::Table 1
DateTime::Duration 2
DateTime::Format::Builder::Parser 3
DateTime::Format::Builder::Parser::Regex 10
DateTime::Infinite::Future 1
DateTime::Infinite::Past 1
DateTime::Locale::en 1
DateTime::TimeZone::Asia::Tokyo 1
DateTime::TimeZone::Floating 2
Encode::Internal 1
Encode::utf8 2
Errno 1
FileHandle 3
HTML::Element 1799
HTML::Element::_travsignal 5
HTML::TreeBuilder::XPath 1
XML::XPathEngine 1
XML::XPathEngine::Expr 19
XML::XPathEngine::Function 6
XML::XPathEngine::Literal 9
XML::XPathEngine::LocationPath 4
XML::XPathEngine::Root 1
XML::XPathEngine::Step 9
utf8 2
つぎ、少しループしてから止めたときの出力
Tracked objects by class:
Config 1
DBI 1
DBI::var 5
DBIx::Class::ResultSource::Table 1
DateTime::Duration 2
DateTime::Format::Builder::Parser 3
DateTime::Format::Builder::Parser::Regex 10
DateTime::Infinite::Future 1
DateTime::Infinite::Past 1
DateTime::Locale::en 1
DateTime::TimeZone::Asia::Tokyo 1
DateTime::TimeZone::Floating 2
Encode::Internal 1
Encode::utf8 2
Errno 1
FileHandle 3
HTML::Element 7378
HTML::Element::_travsignal 5
HTML::TreeBuilder::XPath 4
XML::XPathEngine 1
XML::XPathEngine::Expr 19
XML::XPathEngine::Function 6
XML::XPathEngine::Literal 9
XML::XPathEngine::LocationPath 4
XML::XPathEngine::Root 1
XML::XPathEngine::Step 9
utf8 2
となって、TreeBuilderがなんかやばいことになってるくさい。
で、マニュアル読んでたら $tree->delete
やれよ!って書いてあった。
TreeBuilderは明示的にdeleteメソッド呼ばないと綺麗になくならないらしい。たぶん常識なのだが、いままでやってなかったわぁ。。
これやったらずいぶんメモリ増えなくなった、でもまだなんか少しずつ増える。でも、Devel::Leak::Objectの出力は処理数あげてもかわらない。
あとはmechがあやしいなぁとおもって毎回newするようにしたらメモリ増えなくなったのであれれとおもってマニュアル見たら、デフォルトではヒストリを無限に記録していくらしい。
なので
WWW::Mechanize->new( stack_depth => 1 )
とかしたら大丈夫になった。これでとりあえず大丈夫かな。
まぁ結論としては、マニュアル読めということです。あと Devel::Leak::Object は簡単で便利。
Class::Component
こういうのは経験的にweakenったほうがいい希ガス。なんともいえませんが。