ブラウザでボタンが押された等のアクションを最終的にワーカーのIPCサービスが処理する場合、 伝達経路が長く、使われるテクノロジーも多いので、ユーザープログラムが煩雑でデバッグもとても大変になります。
そこで、2つのライブラリを使ってこの複雑さを隠蔽し、JavaScriptからWorkerのネイティブコードを呼び出すことができるようにしました。
(利用イメージ)
cgiコントローラ内に次のように記述する。
require "al_form" require "al_worker_ipc" class AlController include AlWorker::IpcAction
var ipc = new Alone.Ipc(); ipc.call( "NAME", { any_parameters: "any value" } );
AlWorker::IpcActionをincludeすることで、すべてのIPCをHTTP経由で外部に公開することになります。
セキュリティー上の理由などにより公開してはならないIPCがある場合、IPCソケットを公開用、非公開用に分離するか、module AlWorker::IpcActionを参考に、独自にメソッドを追加してください。
画面上のカウンタ(数字)を、ボタン操作によってアップダウンさせる。
あらかじめ、ウェブサーバーと同じマシンで実行しておく。
require "al_worker_ipc" class CountServer < AlWorker def initialize2() @ipc = Ipc.new() @ipc.chmod = 0666 @ipc.run( self ) set_value( "counter", 0 ) end # IPCコマンド counter を定義 # (note) # 引数 param には、JavaScript側の callで指定したパラメータがそのまま渡ってくる。 def ipc_counter( sock, param ) counter = get_value( "counter" ) case param["work"] when "up" counter += 1 when "down" counter -= 1 end set_value( "counter", counter ) # 第4引数は、JavaScript側へそのまま返される。 reply( sock, 200, "OK", {"counter"=>counter} ) end end server = CountServer.new( "count_server" ) server.parse_option() server.daemon()
require "al_template" require "al_form" require "al_worker_ipc" class AlController include AlWorker::IpcAction def initialize() @ipc = AlWorker::Ipc.open( "/tmp/count_server" ) end def action_index() @ipc.get_values() AlTemplate.run( "index.rhtml" ) end end
<%= header_section %> <script type="text/javascript" src="/js/alone.js"></script> <script type="text/javascript"> function count( work ) { var ipc = new Alone.Ipc(); // コールバックハンドラ。reply() の戻り値は、引数 data で渡される。 ipc.success = function( data, status ) { var e = document.getElementById( "counter" ); e.innerHTML = data.counter; } // サーバーの ipc_counterメソッドをパラメータを付けて呼び出す。 ipc.call( "counter", { work: work } ); } </script> <%= body_section %> カウンター <span id="counter"><%=h @ipc.values["counter"] %></span><br> <input type="button" value="UP" onclick="count('up');"> <input type="button" value="DOWN" onclick="count('down');"> <%= footer_section %>
IPCの戻り値
success コールバックファンクションの第一パラメータで取得する方法と、ipc オブジェクトの、dataアトリビュートで取得する方法の2種類があります。
一般的にはコールバックファンクションを使う方が、やりやすいでしょう。
AJAX
jQueryが読み込まれていれば、AJAX接続にjQuery.ajax メソッドを使うようになります。
その場合、ipc.options が jQuery.ajax メソッド用の接続オプションとして使われますので、接続条件などを変更できます。
IPCの接続先指定の方法は、4種類あります。
1. コントローラのコンストラクタ等で @ipc オブジェクトを生成する。(推奨)
def initialize() @ipc = AlWorker::Ipc.open( "/tmp/chat_server" )
2. コントローラのコンストラクタ等で、@ipc_name でソケット名を与える。
def initialize() @ipc_name = "/tmp/chat_server"
3. httpリクエストに含める
JavaScriptから
ipc.call( "say", { message: "anything", ipc_name: "/tmp/chat_server" } );
4. デフォルト値を使用
何も指示しなければ、/tmp/al_worker をデフォルト値として使用し、IPC接続しようとする。
リクエストパラメータは、以下のようになります。
http://*.cgi?ctrl=xxx&action=ipc&ipc=IPCNAME&arg=ARGUMENT_encoded_by_json
パラメータ | 意味 | 備考 |
---|---|---|
ctrl | Aloneコントローラ | |
action | Aloneアクション | ipc固定 |
ipc | IPC名の指示 | |
arg | 引数 JSONエンコード |
以下の、2要素の配列が返ります。
[IPCステータスコード, 戻り値をJSONエンコード]
index | 内容 | データタイプ | 保存先 |
---|---|---|---|
0 | IPCステータスコード | String | ipc.status_code |
1 | 戻り値 | Hash(Object) | ipc.data |