2009-05-05
■ nsIInputStreamPumpの非同期処理にジェネレータを使う

こいつの使いかたをググると、onDataAvailableのたびに配列(メッセージキュー)に並べておいて、上から順番に処理するコードがよく見つかる。
実はAjaxのとき話題になったんだが、ジェネレータで、こういった非同期処理を同期処理のように書ける。
この実験のために、いわゆるechoサーバをlocalhostの60000番ポートに立ててある。
"yield" == "onDataAvailableまでsleep".
function nettest() {
//ソケット(トランスポート)を作る
let TransportService = Cc["@mozilla.org/network/socket-transport-service;1"].
getService(Ci.nsISocketTransportService);
let transport = TransportService.createTransport(null, 0, "localhost", 60000, null);
let line = {};
//非同期処理にジェネレータを渡す。
callWithClientSocket(transport, function(cistream, costream) {
//サーバに"hello\n"を送って、
costream.writeString("hello\n");
//待つ。
yield;
//サーバから返事が来たら1行読む。
cistream.readLine(line);
//コンソールにプリント。
p(line.value);
//サーバに"world\n"を送って、
costream.writeString("world\n");
//待つ。
yield;
//サーバから返事が来たら1行読む。
cistream.readLine(line);
p(line.value);
//サーバに"こんにちは\nせかい"を送って(UTF-8でおk)
costream.writeString("こんにちは\n");
costream.writeString("せかい");
//待つ.
yield;
cistream.readLine(line);
p(line.value);
cistream.readLine(line);
p(line.value);
yield;
});
}
function socketInputStream(aTransport) {
//ソケットの入力ストリームをとる
let istream = aTransport.openInputStream(0, 0, 0);
//ソケットの入力ストリームの文字コードをUTF-8にする
let cistream = Cc["@mozilla.org/intl/converter-input-stream;1"].
createInstance(Ci.nsIConverterInputStream);
cistream.init(istream, "UTF-8", 0, Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
//ソケットの入力ストリームを行単位で読むようにする
cistream.QueryInterface(Ci.nsIUnicharLineInputStream);
//ソケットの入力ストリームの非同期ポンプをとる
let pump = Cc["@mozilla.org/network/input-stream-pump;1"].
createInstance(Ci.nsIInputStreamPump);
pump.init(istream, -1, -1, 0, 0, false);
return [pump, cistream];
}
function socketOutputStream(aTransport) {
//ソケットの出力ストリームをとる
let ostream = aTransport.openOutputStream(0, 0, 0);
//ソケットの入力ストリームの文字コードをUTF-8にする
let costream = Cc["@mozilla.org/intl/converter-output-stream;1"].
createInstance(Ci.nsIConverterOutputStream);
costream.init(ostream, "UTF-8", 0, Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
return costream;
}
function callWithClientSocket(aTransport, aProc) {
//ソケットの入出力ストリームと、非同期ポンプをとる。
let [pump, cistream] = socketInputStream(aTransport);
let costream = socketOutputStream(aTransport);
// Javascript 1.7 の新機能、ジェネレータを作る。
let generator = aProc(cistream, costream);
//非同期ポンプのリスナ
let listener = {
generator: generator, //onDataAvailableでの"環境"はちょっと特殊。
transport: aTransport, //onDataAvailableでの"環境"はちょっと特殊。
onStartRequest: function onStartRequest(channel, context) {
},
onStopRequest: function onStopRequest(channel, context, status, errorMsg) {
this.generator.close();
this.transport.close(null);
},
onDataAvailable: function onDataAvailable(channel, socketContext, inputStream, sourceOffset, count) {
//非同期ポンプにデータが来るたびに、ジェネレータを進める。
this.generator.next();
}
};
generator.next(); //こいつをonStartRequestに書くと動かないのは、なんで?
pump.asyncRead(listener, null);
}
小ネタ
- Firefox3拡張を書くなら、もうvarは捨ててletでいいとのこと(id:nanto_viさんに教えてもらった。thx.)。C言語構文の皮をかぶったSchemeの世界征服計画が進んでいるぜ。ふっふっふ。
- echoサーバはGaucheユーザリファレンス: gauche.selector - 簡単なディスパッチャからパクった。
- 最近は、XPCOMのIOやソケットの、Gauche風のラッパーを書きためている。callWithClientSocketという関数名もGaucheからパクった。
- Ajaxにジェネレータを使うのは有名だけど、"nsIInputStreamPump yield"でググっても出てこない。既出だったら教えてください。
コメントを書く
トラックバック - http://d.hatena.ne.jp/Gemma/20090505/1241497539
リンク元
- 99 http://www.google.co.jp/search?q=ktkrリーダー&lr=lang_ja&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:ja:official&client=firefox-a
- 54 http://ktk-reader.appspot.com/
- 36 http://www.google.co.jp/search?q=関数型言語&sourceid=navclient-ff&ie=UTF-8&rlz=1B3GGGL_jaJP268JP269
- 33 http://racanhack.sourceforge.jp/rhdoc/index.html
- 33 http://www.google.co.jp/search?hl=ja&q=ktkrリーダー&lr=
- 30 http://www.google.co.jp/search?hl=ja&client=firefox-a&rls=org.mozilla:ja:official&hs=zVF&q=google+reader+2ch&btnG=検索&lr=lang_ja
- 25 http://www.google.co.jp/search?hl=ja&q=関数型言語&sourceid=navclient-ff&rlz=1B5GGGL_jaJP316JP316&ie=UTF-8
- 24 http://www.google.co.jp/search?hl=ja&lr=lang_ja&client=firefox-a&rls=org.mozilla:ja:official&hs=QdK&q=ktkrリーダー&revid=793116747&ei=_TgASuSIGZD6kAXQ86SDBw&sa=X&oi=revisions_inline&resnum=0&ct=top-revision&cd=1
- 19 http://gemmat.s206.xrea.com/matome/matome.cgi
- 17 http://b.hatena.ne.jp/entry/9507499/ マリオのジャンプ実装法とVerlet積分(実践編) - Gemmaの日記
