はちゅにっき

こっちのブログはまったり更新

環境変数で config を切替えるためのクラス

id:cho45 さんが作成された Config::ENV という Perl モジュールがとても便利で、最近設定ファイルが必要な場合には、ほとんどのケースでこのモジュールを利用しています。
使い方については Advent Calendar に掲載された、以下の記事を読んでください。

環境変数で config を切替えるためのモジュール
http://perl-users.jp/articles/advent-calendar/2011/hacker/1

ということで、まれによく使う PHP でも同じことが出来たら便利なんじゃないかと思い、作成してみました。

php-Config-ENV
https://github.com/hatyuki/php-Config-ENV

Perl のように DSL っぽい書き方は出来ませんが、だいたい同じようなことができます。

続きを読む

unstable からパッケージを借りて nginx 1.4.1 をインストール

Debian/weedy がリリースされたため、普段利用している環境も Debian/jessie へとアップグレードされました。
ということで(?)、前回の記事で CentOS に nginx 1.4.0 をインストールしましたが Debian/jessie にも SPDY 対応版の nginx をインストールすることに。
ただし jessie 標準パッケージでは nginx のバージョンが 1.2.6 となっているので、sid (unstable) からパッケージを借りてのインストールとなりました。
Debian のバージョンや、インストールするパッケージに依存せず、unstable からパッケージを借りてのインストールする場合の作業方法となるため、メモメモ。

続きを読む

nginx 1.4.0 の SPDY を試してみる

nginx 1.3 の頃より patch をあてて SPDY を有効する方法を、色々な方が試されていますので、今更という感じはしますが nginx 1.4 がリリースされ SPDY と WebSocket が正式にサポートされたということで、改めて導入してみました。
ということでインストールメモ。

続きを読む

HTML5 の canvas をさわってみた

仕事をしている時、ちょっと QR コードが欲しくなったけれど、手軽に生成できるサイトが見つけられなかったので、HTML5 の練習も含めて作ってみることにしました。
作ったのはこんな感じ。

Zebra
http://qr.magicalhat.jp/
github
https://github.com/hatyuki/Zebra

テキストエリアに何か入力すると、それをリアルタイムで QR コードに変換してくれます。
たとえば般若心経を入力するとこんな QR コードが生成されます。誰得なんでしょうね。
って、何の変哲もない QR コードなんだけど。。。
f:id:magicalhat:20130405010237p:plain

続きを読む

jperl と jcode.pl から卒業する

何をいまさらな話題ですが、文字コードEUC-JP が主流だった時代に作られた jperl と jcode.pl に依存しているレガシーなシステムをモダンな Perl に書き換える場合には、Encode に加えて Encode::EUCJPMS を使うと簡単でした。
というメモ。

Encode-EUCJPMS
http://search.cpan.org/~naruse/Encode-EUCJPMS/

これで機種依存文字を恐れず処理することができました。

Unicode にさえなってしまえば後はやり放題で、日本語の「全角←→半角」変換などは Lingua::JA::Regular::Unicode が便利でした。

Lingua-JA-Regular-Unicode
http://search.cpan.org/~tokuhirom/Lingua-JA-Regular-Unicode/
use utf8;
use Encode::EUCJPMS;
use Encode ( );

# eucJP-ms な DB から値を取得して
my $row = $sth->fetchrow_hashref( );

# Perl の世界に decode して
my $utf8 = Encode::decode('eucJP-ms', $row->{japanese});

...
# なんか処理して
...

# eucJP-ms で戻してあげる
$dbh->execute(Encode::encode('eucJP-ms', $japanese));

こんな感じ。
ちなみに、今回は DB からいろいろ取得して、文字列処理をして DB に戻す。という、だいたい完了まで 30分くらい処理にかかるようなスクリプトを書き直したのですが、書き直した後も実行時間は特に変わらず *1 Encode でいったん EUC-JP から Unicode に変換し、再び EUC-JP に戻すこと自体はパフォーマンス的なマイナスはないと思います。
むしろ jperl から脱却することによるメリットの方がおおきいですね。
これで「触らぬ Script に障害なし」とか言う謎の遺言からも解放です。
わーい。楽ちんですね。

*1:実際は 5分くらい早くなった

Debian/Wheezy を TimeMachine のディスクとして使う

TimeCapsule はちょっとオーバースペックなんだもの。
ということで、Debian/Wheezy に netatalk をインストールして TimeMachine のディスクとして利用してみました。
調べてみると netatalk のバージョンが 2.1 未満の場合はソースからコンパイルして〜。みたいなことがあるようですが、Wheezy では最初から 2.2 がインストールされたので、作業は本当に netatalk をインストールしただけでした。

# aptitude install netatalk

おわり。
申し訳程度に以下の設定ファイルをちょっと編集しました。

  • /etc/netatalk/AppleVolumes.default
--- AppleVolumes.default        2013-01-04 00:50:31.000000000 +0900
+++ /etc/netatalk/AppleVolumes.default  2013-01-03 12:55:25.000000000 +0900
@@ -174,6 +174,7 @@
 :DEFAULT: options:upriv,usedots
 
 # By default all users have access to their home directories.
-~/                     "Home Directory"
+# ~/                   "Home Directory"
+/path/to/TimeMachine/dir "TimeMachine" options:tm volsizelimit:100000
 
 # End of File

TimeMachine で利用するディレクトリの指定と、クォータの設定をしただけっていう。すごく簡単ですね。
これで無事にバックアップが作成されるようになりました。わーい。

WebSocket を使って Amon2 でチャットプログラムを書いてみる

ずいぶん前ですが Amon2 が WebSocket に対応したということで、今更感のあるチャットプログラムを書いてみることに。
今更とは言いつつも社内では IRC を使うことができないので、ちょっとしたメッセージがやりとりできるものを作ってみようかなと思い、そのベースとなるようなイメージで作ってみました。
オマケで以前から使ってみたいなぁと思っていた Redis や Proclet なんかも (無駄に) 使ってみました。
適当な Heartbeat で WebSocket を維持していたり、エラー処理が適当すぎて Member の一覧が嘘つきだったり *1 と、まだまだイケてない部分ばかりですが、最近時間がなかなか取れないこともあり、とりあえず動くし晒してみようかと思います。
Twincle の名前は昔テストで Twitter Client を作ったときに押さえた ID をそのまま踏襲しただけで、特に意味はないです。
README すらないご覧のザマだよ。

hatyuki / twincle
https://github.com/hatyuki/twincle
デモ
http://twincle.magicalhat.jp/

セッションで Socket を管理しているため、同一ブラウザで2つウィンドウ立ち上げてもうまく動きません。この辺は Hash::MultiValue をうまく使えばいいのかなー。などと検討中。

なんとなく工夫した気がするところ

WebSocket ではバイナリデータを送受信することができるので、今回は Perl (Amon2) ←→ JavaScript 間を MessagePack でバイナリ化してやりとりをしてみました。
Amon2 では下位のレイヤーでは Protocol::WebSocket を利用して WebSocket のやりとりをしていますが、その部分は見事に隠蔽されており、プログラムするときは Protocol::WebSocket の存在を意識せずに、文字列を単に渡すだけで WebSocket を扱うことができます。

  • MyApp::Web::Dispatcher
get '/socket' => sub {
    my $c = shift;

    $c->websocket( sub {
        my $ws = shift;
        $ws->send_message("文字列を渡すだけで OK");
        # ...
    } );
};

が、バイナリデータを送受信するためには Protocol::WebSocket::Frame のコンストラクタで送信したいフレームがバイナリデータであることを指定する必要があるため、ちょっと都合が悪いこととなります。
そこで、Amon2::Plugin::Web::WebSocket をちょっとだけ編集して、文字列だけではなく Protocol::WebSocket::Frame そのものも渡せるようにしました。

  • MyApp::Plugin::Web::WebSocket
# ... (中略)
$ws->{send_message} = sub {
    my $message = shift;

    # Protocol::WebSocket::Frame オブジェクトを受け付けるように
    unless (eval { $message->isa('Protocol::WebSocket::Frame') }) {
        $message = Protocol::WebSocket::Frame->new($message);
    }

    $h->push_write($message->to_bytes);
};
# ... (中略)

これにより以下のように、バイナリフレームを送信することができるようになります。

  • MyApp::Web::Dispatcher
get '/socket' => sub {
    my $c = shift;

    $c->websocket( sub {
        my $ws = shift;

        # バイナリフレームを作成して
        my $frame = Protocol::WebSocket::Frame->new(
            type => 'binary',
            buffer => $binary_strings,
        );

        # 送信
        $ws->send_message($frame);
        # ...
    } );
};

無駄にハマって解決できていないところ

手元の Mac では再現しませんが、Debian 上で実行するとなぜか LWP::UserAgent がすごい時間がかかる。
具体的には不自然に必ず30秒以上かかる。なんかタイムアウトを待っているみたいな。。。
そのせいで Net::Twitter::Lite を使った Twitter の認証に必要以上の時間がかかってしまい、困ったことになりました。
とりあえずの対処として、Net::Twitter::Lite が LWP::UserAgent ではなく Furl を使うように無理矢理パッチをあてました。

package Twincle::Auth::Site::Twitter;
use strict;
use warnings;
use Furl;
use Net::Twitter::Lite;

sub import
{
    no warnings 'redefine';

    # "default_header" メソッドがないとエラーになるので申し訳程度に追加
    *Furl::default_header = sub { };

    my $orig = *Net::Twitter::Lite::new{CODE};
    *Net::Twitter::Lite::new = sub {
        my ($class, %args) = @_;

        # UserAgent を LWP::UserAgent から Furl に差し替え
        $args{ua} = Furl->new;
        $args{legacy_lists_api} = 0;

        $orig->($class, %args);
    };
}

1;

LWP::UserAgent が遅い原因については据え置き中。
時間があるときに調べてみよっと。

まとめ

Amon2 の WebSocket サポートを使うと、すごく簡単に WebSocket を使うアプリケーションが作成できました。
バイナリデータを送受信するために改良した部分は、もう少し確認して本家の方へ pull request してみたいなぁと思います。
まだまだ追加したい機能はたくさんありますが WebSocket や Redis など、使ってみたかったものを使いつつ動くということで
わーい。

*1:きちんとログアウトしないと幽霊部員になる