userstreamapi おまけ

前の続き。


LWP::UserAgentを眺めていたら
http://perldoc.jp/docs/modules/libwww-perl-5.813/LWP/UserAgent.pod#item__ua__gt_get___url__

:content_cb オプションでコールバック関数が指定されると、
レスポンスの内容の塊ををサーバから受信する毎にこの関数が呼び出されます。
これらのオプションのどちらも指定されなかった場合、レスポンスの内容は
レスポンスオブジェクト自身に蓄積されます。
これはレスポンスボディがとても大きい場合には向いていません。


':content_cb'でコールバックを指定すればLWPでもいけるんじゃ?
以下で試してみる。

my $ua = new LWP::UserAgent();
my $header = makeOAuthHeader(...); # Authorizationヘッダ部分

my $buffer; # コールバック関数内で使用するバッファを先に生成
$ua->get('https://userstream.twitter.com/2/user.json',
	"Authorization"=>$header,
	"Content-Type" => "application/x-www-form-urlencoded",
	":content_cb"  => sub{
		$buffer .= shift;
		my $re = shift;
		printf STDERR ("as_string: %s\n", $re->as_string); # ヘッダ部分とコンテンツ部分を出力
		while($buffer =~/(.+?\n)/g){
			my $line = $1;
			print "$line";
		}
		$buffer = substr($buffer, rindex($buffer,"\n")+1);
	}
);

改行コードを"\n"で決めうちしている点でちょっと雑だけど、
こんな感じにやってみるとうまい具合に標準出力にJSONデータが出力された。
HTTP::Request->as_stringでHTTPレスポンスヘッダ部分とコンテンツ部分を確認してみても、
ヘッダ部分は一番最初に取得した状態を記憶しているだけで、コンテンツ部分はコールバックされるたびにクリアされているので、
バッファがあふれる可能性は低い。
コールバック関数が呼ばれるタイミングは、1行毎ではなく':read_size_hint'の大きさに依存する。
なので、自前でバッファを作って、改行データまでを1データとしてwhileで回して処理すればよい。


$buffer = substr($buffer, rindex($buffer,"\n")+1);の部分は、
もし、改行が見つからない場合はrindex()は-1となり、結果に+1されるので0になる。
substrで得られるのは本来の文字列になるので、バッファは書き換わらない事になる。
本来ならif文で分けるべきだが、面倒なのでry


1行あたりのデータの最大サイズが決まっているのであればいいんだけど、
中身はテキストデータだし、そこまで大きすぎることはないか。