目次

AlWorker JavaScriptからIPCをコールする

背景

ブラウザでボタンが押された等のアクションを最終的にワーカーのIPCサービスが処理する場合、 伝達経路が長く、使われるテクノロジーも多いので、ユーザープログラムが煩雑でデバッグもとても大変になります。

そこで、2つのライブラリを使ってこの複雑さを隠蔽し、JavaScriptからWorkerのネイティブコードを呼び出すことができるようにしました。

(利用イメージ)

使い方

1. JavaScript "alone.js" ライブラリを読み込む

htmlで、alone.jsが読み込まれる様に記述する。

<script type="text/javascript" src="/PATH/TO/alone.js"></script>

2. AlControllerへIpcActionモジュールをincludeする

cgiコントローラ内に次のように記述する。

require "al_form"
require "al_worker_ipc"
 
class AlController
  include AlWorker::IpcAction

3. JavaScriptからコールする

var ipc = new Alone.Ipc();
ipc.call( "NAME", { any_parameters: "any value" } );

注意

AlWorker::IpcActionをincludeすることで、すべてのIPCをHTTP経由で外部に公開することになります。
セキュリティー上の理由などにより公開してはならないIPCがある場合、IPCソケットを公開用、非公開用に分離するか、module AlWorker::IpcActionを参考に、独自にメソッドを追加してください。

サンプル

画面上のカウンタ(数字)を、ボタン操作によってアップダウンさせる。

常駐サーバー

あらかじめ、ウェブサーバーと同じマシンで実行しておく。

count_server.rb
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()

Alone cgiコントローラ

main.rb
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

画面テンプレートとJavaScript

index.rhtml
<%= 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 %>

個別機能

JavaScript ライブラリ

IPCの戻り値

success コールバックファンクションの第一パラメータで取得する方法と、ipc オブジェクトの、dataアトリビュートで取得する方法の2種類があります。
一般的にはコールバックファンクションを使う方が、やりやすいでしょう。

AJAX

jQueryが読み込まれていれば、AJAX接続にjQuery.ajax メソッドを使うようになります。
その場合、ipc.options が jQuery.ajax メソッド用の接続オプションとして使われますので、接続条件などを変更できます。

IPC接続先指定

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接続しようとする。

プロトコル詳細

cgiリクエスト

リクエストパラメータは、以下のようになります。

http://*.cgi?ctrl=xxx&action=ipc&ipc=IPCNAME&arg=ARGUMENT_encoded_by_json
パラメータ意味備考
ctrlAloneコントローラ
actionAloneアクションipc固定
ipcIPC名の指示
arg引数 JSONエンコード

戻り値

以下の、2要素の配列が返ります。

[IPCステータスコード, 戻り値をJSONエンコード]

index内容データタイプ保存先
0IPCステータスコードStringipc.status_code
1戻り値Hash(Object)ipc.data