読者です 読者をやめる 読者になる 読者になる

WebSocketでブラウザにプッシュ配信する - MessagePack-RPC+Rev-WebSocket

先日、WebSocketのサーバライブラリ Rev-WebSocket をリリースしました。
前回のエントリではブラウザ同士で通信するチャットアプリケーションを紹介しましたが、実際にはTwitterクローラやWebアプリケーションなど、別のプログラムと連携してブラウザにプッシュ配信したくなると思います。

つまり↓このように、任意のプログラムからWebSocketサーバを経由して、ブラウザにデータをプッシュ配信します:


http://github.com/frsyuki/rev-websocket


プッシュ配信したいアプリケーションと WebSocket サーバの間は MessagePack-RPC で繋ぎます。
Rev-WebSocket と MessagePack-RPC は相性が良く、簡単に統合することができます*1


アプリケーションから WebSocket サーバを経由してブラウザにデータを配信するコードは、↓このようになります。

require 'rubygems'
require 'msgpack/rpc'    # gem install msgpack-rpc
require 'json'

# WebSocketサーバへのRPCセッションを作成
$ws = MessagePack::RPC::Client.new('127.0.0.1', 18800)

# プッシュ配信
$ws.call(:push_data, {"hello" => "world"}.to_json)

簡単ですね! ここではRubyを使っていますが、MessagePack-RPCが対応していれば他の言語からも配信できます(C++JavaPerlなど)。
$ws はどこからでも使い回せます。


WebSocketサーバは↓このようになります。

require 'rubygems'
require 'rev/websocket'  # gem install rev-websocket
require 'msgpack/rpc'    # gem install msgpack-rpc

$sockets = {}

class MyConnection < Rev::WebSocket
  # 接続されたら呼ばれる
  def on_open
    puts "WebSocket opened from '#{peeraddr[2]}': request=#{request.inspect}"
    $sockets[self] = self
  end

  # メッセージが届いたら呼ばれる
  def on_message(data)
    puts "WebSocket data received: '#{data}'"
  end

  # 切断されたら呼ばれる
  def on_close
    puts "WebSocket closed"
    $sockets.delete(self)
  end
end

class RPCServer
  # すべてのブラウザに配信
  def push_data(data)
    $sockets.each_value {|sock|
      sock.send_message(data)
    }
    nil
  end
end

# イベントループを作成
loop = Rev::Loop.default

port = ARGV[0] || 8080

# イベントループにWebSocketサーバを登録
ws = Rev::WebSocketServer.new('0.0.0.0', port, MyConnection)
ws.attach(loop)

# 同じイベントループにRPCサーバも乗せる
rpc = MessagePack::RPC::Server.new(loop)
rpc.listen('127.0.0.1', 18800, RPCServer.new)

# イベントループを開始
loop.run

このプログラムを起動しておけば、他のアプリケーションからブラウザにプッシュ配信ができるという仕組みです。


実際に動くサンプルコードが frsyuki's rev-websocket at github に入っています。
他のサンプルと併せてチェックしてみてください。

*1:両方ともRevを使っているため、Rev-WebSocket と MessagePack-RPC サーバの両方を同じI/Oループに乗せることができます。