Erlang で付箋Webアプリケーションを作ってみました。
インターネットを見ていて、そのときの感想とかページの内容に対して思っ たことなんかを簡単に書き留めておけると便利かなと思い、適当なWebのペー ジ上にブラウザで表示したまま付箋をつけられる WEB アプリケーションを、最近流 行の Erlang 作成してみました。
付箋 Web の実験デモサイトはこちらです。
Erlangを使う必要があったわけではないですが、面白そうなので練習を兼ねて はじめて使ってみました。
付箋Webの概要は
- 付箋のデータは専用の付箋Webサーバ上に保存される。
- ブラウザー上ではAjaxで付箋Webサーバと通信する。
- ブックマークレットを使って、任意のページで付箋を使えるようにする。
実際に作成しようとすると、他人のページに、ほかのサーバのデータを使って 重ね書きするので工夫が必要になります。最初に考えたのは、IFRAMEを使って 他人のページを表示する方法でしたが、これだけだと使いづらいので、ブック マークレットを使って表示中のページに付箋をつけられるようにしました。
IFRAMEタイプ
ブックマークレットタイプ
次にサーバサイドのErlangの説明をしたいと思います。
サーバサイドでは、Erlang で動作するHTTPサーバー Yaws を使用しています。Apacheと比較 しているサイト
http://www.sics.se/~joe/apachevsyaws.htmlをみるとYawsは並列処理では圧倒的に速いようです。
#日本語読みはわかりませんが、内輪では「よーず」になりました。
debian パッケージの yaws が動作しないためソースからコンパイルしてイン ストールしました。設定は /usr/local/etc/yaws.conf に設定します。
以下 該当部分の抜粋 です
# --- 追加のerlangモジュールにパスを通す ebin_dir = 追加モジュールのあるパス # --- 起動時に起動する追加のプロセスを指定 run_mod=urlidx # サーバの設定 <server サーバ名> port = ポート番号 listen = 0.0.0.0 docroot = ドキュメントのパス </server>
実行するには
$ yaws -i
を実行します。オプションに --daemon を指定するとデーモンで起動します。
yawsを使っただけではErlangを使った面白みが無いので、データの保存に Erlangのdetsを使用してデータベースをつくり、それの管理用にErlangのプロ セスを上げてyawsのクライアントのプロセスと通信させて見ました。上記の yaws.conf内にある"run_mod = urlidx "がdetsデータベース用のプロセスを yaws起動時に立ち上げる指定になります。
データーベースの図
実際にプロセスとして立ち上げたのは、URL別のデータベースに対するインデッ クス情報を持ったデータベースの管理用だけです。この形であればurlidxプロ セスが付箋データのプロセスを立ち上げ、それをクライアントプロセスに渡す べきですが、今回はまだ、クライアントプロセスが直接付箋データベースを操 作するようになっています。
Erlangの特徴のひとつとして、Erlang独自のプロセスの起動とそのプロセス間 の通信が非常に容易にできることがあります。Erlangのプロセス間通信はプロ セスごとメールスロットを介して行われます。レシーブ側はメッセージをキュー に入れて、順番にパターンマッチし、パターンマッチしないメッセージは再度 キューに入れられます。
送信側 - メッセージの送信 プロセスID ! メッセージ 受信側 - メッセージを受信 receive パターン1 -> 実行 ..., パターン2 -> 実行 ....
以下は付箋のコード内での実行例です。
データベースプロセス。(urlidx.erl)
(Yaws起動時に実行されている。)
start() -> spawn(?MODULE, urldb, [] ). --- プロセスを生成 urldb() -> dets:open_file(urldb, ?DETSOPT), process_flag(trap_exit, true), register(url_indexer, self()), loop(). loop() -> receive --- 受信待ち {newdb, Url, ClientPid } -> ---- (1) ClientPid ! get_note_db(newdb,Url); ----- 返信(1) {getdb, Url, ClientPid } -> ----(1) ClientPid ! get_note_db(getdb,Url); ----- 返信(1) {all,ClientPid} -> ----(2) ClientPid ! all_url_list() ----- 返信(3) end, loop().
Erlangでは、変数は大文字で始まります。小文字で始まるものはatomと呼ばれ、 定数のように使われます。Yawsを起動するとyaws.confの設定に従ってデータ ベースプロセスが起動され、プロセスをurl_indexerの名前で登録してから loopでメッセージの受信待ちを行っています。
クライアントのコード
get_note_db(Url,Opt) -> url_indexer ! {Opt,Url,self()}, --- 送信(1) receive --- 応答の受信待ち .... 返信(1) または 返信(2)を受信 {ok,NoteRef} -> {ok,NoteRef}; {err,Msg} -> {err,Msg} end. all_url()-> url_indexer ! {all,self()}, --- 送信(2) receive --- 応答の受信待ち ... 返信(3)を受信 [] -> "//Index is Null."; [S|N]-> Str = "\""++S++"\"", [ "[" ++ list_join(Str, N, ",") ++ "]" ] end.
クライアントからはurl_indexerプロセスにメッセージを送っています。クラ イアントのget_note_db()内の送信(1)では3要素のタプルを送っていて最初の 要素はatomが代入されている変数になっています。3要素目はクライアント自 身のプロセスになります。受信側では、3要素のタプルで最初の要素のatomが 一致するところでパターンが一致しクライアントのプロセスにメッセージを返 信しています。all_url()では2要素のタプルで最初の要素がatomのallになっ ていいるのでデータベースプロセス側ではパターンマッチして返信(3)を返し ます。
ご覧のように Erlang ではプロセスの作成とプロセス間通信が非常に簡単に行 えることが魅力だと思います。今回のようなケースであれば、データベースに わざわざ Erlang を使う必要は無いかもしれませんが、Erlang前提でシステム の設計を考えると新しい発想でシステムを考えるきっかけになるかと思います。
Yawsのエスケープ処理について
今回、クライアントからはすべてエスケープ処理されたデータがGETで送られ てくるのですが、Yawsではエスケープ処理の部分が日本語に対応していません。 そこで、中身をみるとパターンマッチだけでできるようなのでパッチを作って みました。
--- yaws-1.68/src/yaws_api.erl.orig 2007-02-02 00:58:33.000000000 +0900 +++ yaws-1.68/src/yaws_api.erl 2007-05-24 16:55:04.000000000 +0900 @@ -398,6 +398,10 @@ %% Key wil always be a regular atom. +do_parse_spec(<<$%,$u, I1:8, I2:8,I3:8,I4:8, Tail/binary>>, Spec, Last, Cur, State) -> + Hex = yaws:hex_to_integer([I1,I2,I3,I4]), + do_parse_spec(Tail, Spec, Last, [ Hex | Cur], State); + do_parse_spec(<<$%, Hi:8, Lo:8, Tail/binary>>, Spec, Last, Cur, State) -> Hex = yaws:hex_to_integer([Hi, Lo]), do_parse_spec(Tail, Spec, Last, [ Hex | Cur], State); @@ -714,6 +718,9 @@ find_cookie_val3([H|T], Ack) -> find_cookie_val3(T, [H|Ack]). +url_decode([$%, $u, U1,U2,U3,U4 | Tail]) -> + Hex = yaws:hex_to_integer([U1, U2, U3, U4]), + [Hex | url_decode(Tail)]; url_decode([$%, Hi, Lo | Tail]) -> Hex = yaws:hex_to_integer([Hi, Lo]), [Hex | url_decode(Tail)]; @@ -783,6 +790,10 @@ [H|url_encode(T)]; true -> case yaws:integer_to_hex(H) of + [I1,I2,I3,I4] -> + [$%, $u, I1,I2,I3,I4 | url_encode(T)]; + [I1,I2,I3] -> + [$%, $u, $0, I1,I2,I3 | url_encode(T)]; [X, Y] -> [$%, X, Y | url_encode(T)]; [X] ->
トラックバックURL
この記事へのトラックバック
この記事へのコメント
ブックマークレット動かすと表示される。
PetaPonというサービスを先日リリースしたものです。http://www.petapon.net/
コンセプトが似ていたので驚きました。共時制ってやつでしょうか?
PetaPonは付箋の位置を、座標ではなくて、テキストマッチで決定しています。
それと、
付箋より、メモ機能付きのMacのダッシュボード的な使い方にしたほうが僕は使う場面が増えそうかも。