sinatra を使用して、サーバーによって開始されたブラウザーにメッセージを表示するためのビルボードを構築しようとしています。サーバーコードで行う最も明白なことは次のようなものでした:
サーバ:
require 'em-websocket'
require 'yajl'
require 'haml'
require 'sinatra/base'
require 'thin'
$channel = EM::Channel.new
EventMachine.run do
class App < Sinatra::Base
get '/' do
haml :index
end
end
EventMachine::WebSocket.start(:host => '0.0.0.0', :port => 8080) do |ws|
ws.onopen {
sid = $channel.subscribe { |msg| ws.send msg }
ws.onmessage { |msg| $channel.push msg}
# the text I periodically send to the server and want to be visible in the connected webbrowsers
1.upto(5) {|i| sleep 3; ws.send "Hello #{i}"} #had to remove this
}
end
App.run!({:port => 3000})
end
index.haml
!!!
%html{:lang => "en"}
%head
%link{:href => "/css/bootstrap.css", :rel => "stylesheet"}
%body
%div#show
%script{:src => "http://code.jquery.com/jquery-1.7.2.min.js"}
%script{:src => "/js/bootstrap.js"}
%script{:src => "/js/app.js"}
app.js
$(function(){
ws = new WebSocket("ws://localhost:8080");
ws.onmessage = function(evt) {
if (evt.data!='done'){
document.getElementById("show").innerHTML = evt.data;
}
};
});
ただし、テキストは最後のスリープ後にブラウザーに一度に表示されるため、最後の行しか表示されません。接続が確立されると、受信メッセージへの反応としてのみ、サーバー側から何かを送信できないようです。
以下のようなRubyクライアントで試してみましたが、テキストを送信するたびに新しい接続を作成する必要があり、ループを .callback または .stream メソッドに入れても機能しません。
require 'em-websocket-client'
def send text
EM.run do
conn = EventMachine::WebSocketClient.connect("ws://localhost:8080")
conn.callback do
conn.send_msg text
conn.send_msg "done"
end
conn.stream do |msg|
puts "<#{msg}>"
if msg.data == "done"
conn.close_connection
end
end
conn.disconnect do
EM::stop_event_loop
end
end
end
1.upto(5) do |i|
sleep 3
send "Hello #{i}"
end
これを達成するためのより良い方法が必要だと思いますが、どの方法でお願いしますか?