2010-11-21

[Node.js] /dev/urandom を延々と出力する HTTP サーバー

Node.js の本体の API にある、http.createServer を使って、ファイルの内容 (Readable Stream) を Class: http.ServerResponse (Writable Stream) に対して随時書き込んで、/dev/urandom から湧き出てくるランダムバイナリをストリーミング出力するとても有意義なサーバーを作ってみました。

以下のコードを node hogehoge.js という感じで実行して、適当に http://localhost:10001/ みたいなアドレスに対して HTTP でアクセスすると、バイナリデータを延々と返してくれます。

ポイント
  • /dev/urandom を、ファイルの内容を Readable Stream で取れるように、fs.createReadStream で開く。
  • HTTP レスポンスオブジェクト: resに対して、res.write で書き込みしていって、送信バッファがいっぱいになった場合、書き込めるようになると発生するイベント: drain まで書き込まずに待つ。

var fs = require('fs'),
    http = require('http'),
    util = require('util'),
    PORT = 10001;

http.createServer(function (req, res) {
    res.writeHead(200, {
        'Content-Type': 'application/octed-stream',
    });

    var stream = fs.createReadStream('/dev/urandom');

    stream.on('data', function (data) {
        console.log('on data: ' + data.length);
        var flushed = res.write(data);

        if (!flushed) {
            console.log("send buffer looks full");
            stream.pause();
        }
    });

    res.on('drain', function () {
        console.log("on drain");
        stream.resume();
    });
}).listen(PORT);

続編に続く
hidekiy blog: [node.js] 続 /dev/urandom を延々と出力する HTTP サーバー

関連記事
urandom streaming on twiggy - tokuhirom's blog.

2010-11-09

[perl] PayPal の ExpressCheckout を使ってみる

PerlからPayPalのExpressCheckoutを使う方法についての記事です。これからはPayPalの時代が来るという記事を読んで自分でもやってみたくなったので、Sandboxアカウントで実際にやってみました。まだ実際にお金を動かしたりはしていないので、至らない点が多々あると思います。

ExpressCheckoutとは、決済手続きの途中でPayPalにリダイレクトして、その後こちら側のサイトに戻ってから最終決断のボタンを押してもらう方式で、決済完了の情報がきちんと伝わらないみたいな中途半端な状態にはならない方式です。

モジュールの選定
PayPal APIは二種類の形式で使うことができて、NVP(Name Value Pair)とSOAPです。

このうち、SOAPを使う、Business::PayPal::API はPayPal APIの更新に追従できていないので良くないです。SOAPを直接いじろうとして、SOAP::Lite を検討しましたが、面倒な感じなのでやめました。

a=b&c=d..のような形式でフォーマットされている素朴極まりないNVPを利用するライブラリ、Business::PayPal::NVP がAPIが更新されても利用できるので良いと思います。

Sandboxアカウントの取得
こちら PayPal Sandbox で誰でも取得できます。Sandboxの中ではお金が使い放題です。

実際のコード

use Business::PayPal::NVP;

# branchでsandbox, 本番サーバーを切り替える
my $paypal = Business::PayPal::NVP->new(
    test => {
        user    => 'info_1287414775_biz_api1.hidekiy.com',
        pwd => 'xxxxxxxxxxx',
        sig => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
        version => 65, # 新しいのをたのむ
    },
    branch => 'test',
);

# 請求金額が確定していて、PayPalでの支払いを希望しているとする。
my %res = $paypal->SetExpressCheckout(
    PAYMENTREQUEST_0_PAYMENTACTION => 'Sale',
    PAYMENTREQUEST_0_AMT => '1000.00',
    PAYMENTREQUEST_0_CURRENCYCODE => 'JPY',
    LOCALECODE => 'JP',             # Sandboxでは効いてないけど、本番ではたぶんOK
    LANDINGPAGE => 'Billing', # ログインだけのページになると寂しいのでBilling
    SOLUTIONTYPE => 'Sole',     # PayPalアカウントを作る必要はなしとする
    RETURNURL => 'http://example.com/return',
    CANCELURL => 'http://example.com/cancel',
);

# $res{ACK}を確認後、
# https://www.sandbox.paypal.com/webscr?cmd=_express-checkout&token=$res{TOKEN}
# にリダイレクトして、支払い手続きをしてもらう。

# http://example.com/returnにPayerIDとtokenを付けて戻ってくる
# 最終決断をしてもらったあと、以下を実行する
my %res = $paypal->DoExpressCheckoutPayment(
    PAYMENTREQUEST_0_PAYMENTACTION => 'Sale',
    PAYMENTREQUEST_0_AMT => '1000.00',
    PAYMENTREQUEST_0_CURRENCYCODE => 'JPY',
    TOKEN => scalar $req->param('token'),
    PAYERID => scalar $req->param('PayerID'),
);
# $res{ACK}を確認して完了

参考資料
Introducing Express Checkout
SetExpressCheckout API Operation
DoExpressCheckoutPayment API Operation

2010-11-08

[linux] SSH経由でrootでrsyncしてサーバーの引っ越し

結論
rootでrsyncしようとsudo rsyncすると、SSHのAgent Forwardingに必要な環境変数をsudoがセキュリティ対策で削除して困ったが、sudo -E rsync とすると上手くいく。

蛇足
2HOSTの方針で、St.Louisのデータセンターが閉鎖されて、そのついでにセキュリティ問題発覚以後開発元がおかしなことになっている HyperVM から SolusVM への移行をすすめるので、新しいVPSノードを再設定できる人は、SolusVM管理下の新しいVPSノードを作るから各自移行してね、というメールが来たので、提案された通りにすることにしました。

そこで、古いサーバーのファイルを持っていくのに、scpでちまちまコピーするのも良いけどファイル数が多いと遅いので、rootでrsyncしてコピーすると良いのではないかと思って、やってみました。

しかし普通にsudo rsyncとすると、エージェントフォワーディングによる公開鍵認証にならないので、なぜなのか悩みましたが、sudoのセキュリティ対策によるものと分かりました。

CentOSでyumで入るsudoの/etc/sudoersはとても安全側に振ってあるみたいで、環境変数は指定されたものは全部削除されてしまい、SSH_AUTH_SOCKが削除されてAgent Forwardingが働きません。参考:sudo env と叩く

sudoのmanページを読むと、その環境変数を削除する機能を一時的に無効にするオプション -E (preserve environment) を追加したら、無事公開鍵により認証され、root権限でのrsyncができました。

実際に使ったコマンドは、
sudo -E rsync --archive --verbose example.com:/etc/ ./example.com-etc
のような感じで、example.com の /etc がローカルの ./example.com-etc に保存されます。

2010-11-06

[perl] Coro::Specific の使いどころについて

Coro とは、AnyEventJSON::XS で有名な Marc Lehmann 作の、Perlにおいて、協調型スレッド(簡単な方のスレッド) を実現して、背後で AnyEvent が仕事をしながら、プログラマ側からは今までのブロッキング方式と思って書けるようにするためのモジュールです。

本体に同梱されている Coro::Specific というモジュールを使うと、今まで fork システムコールで多重化していた Net::Server のような、サーバーのインスタンスが1つで、それぞれのクライアントがプロパティをちょこっと書き換える型のサーバーを Coro 化するのに役に立ちます。

実際に、Coro における PSGI サーバー実装である Corona で使っている、Net::Server::Coro では、以下のようにして特定のプロパティをコルーチンごとに別々に設定できるようにしています。

# Net::Server::Coro::post_bind_hook 付近より抜粋
# $self はサーバーのインスタンス

foreach my $key (qw(client sockaddr sockport peeraddr peerport peerhost)) {
    tie $self->{server}{$key}, Coro::Specific::;
}