2010-06-08 16 views
35

Używam Sinatry już od jakiegoś czasu i chciałbym dodać kilka funkcji czasu rzeczywistego do mojej aplikacji internetowej, przesyłając dane za pośrednictwem stron internetowych.Jakiś sukces z Sinatrą współpracującą z EventMachine WebSockets?

Z powodzeniem użyłem gem 'em-websocket' na własną rękę, ale nie byłem w stanie napisać jednego pliku ruby, który ma serwer WWW Sinatra I serwer gniazda sieciowego.

Próbowałem kręcić biegiem! lub zacznij! metody w oddzielnych wątkach bez powodzenia.

Czy ktoś to zrobił?

Chcę mieć je w tym samym pliku, co mogę, a następnie udostępnić zmienne między dwoma serwerami.

Dzięki!

Odpowiedz

26

nie spróbować, ale nie powinno być zbyt trudne:

require 'em-websocket' 
require 'sinatra/base' 
require 'thin' 

EM.run do 
    class App < Sinatra::Base 
    # Sinatra code here 
    end 

    EM::WebSocket.start(:host => '0.0.0.0', :port => 3001) do 
    # Websocket code here 
    end 

    # You could also use Rainbows! instead of Thin. 
    # Any EM based Rack handler should do. 
    Thin::Server.start App, '0.0.0.0', 3000 
end 

Również Cramp ma wdrożenie websocket który działa bezpośrednio z cienkimi/Rainbows! możesz być w stanie wyodrębnić, więc nie będziesz musiał nawet uruchamiać serwera na innym porcie.

+0

Tak właśnie zrobiłem. Mam jednak powiązane pytanie, w jaki sposób mogę odszyfrować 'Rack :: Server :: Cookie' (ustawione w klasie' Sinatra') zwracane w 'handshake' przekazanym przez klienta do' ws.onopen'. Zobacz moje pytanie bardziej szczegółowo na http://stackoverflow.com/questions/16312024/how-to-decode-a-cookie-from-the-head-of-a-websocket-connection-handshake-rub –

20

Dzięki Konstantin ... to zadziałało! Musiałem nieco poprawić twój kod. Dodałem komentarze, gdzie to zmieniłem.

-poul

require 'rubygems'  # <-- Added this require 
require 'em-websocket' 
require 'sinatra/base' 
require 'thin' 

EventMachine.run do  # <-- Changed EM to EventMachine 
    class App < Sinatra::Base 
     get '/' do 
      return "foo" 
     end 
    end 

    EventMachine::WebSocket.start(:host => '0.0.0.0', :port => 8080) do |ws| # <-- Added |ws| 
     # Websocket code here 
     ws.onopen { 
      ws.send "connected!!!!" 
     } 

     ws.onmessage { |msg| 
      puts "got message #{msg}" 
     } 

     ws.onclose { 
      ws.send "WebSocket closed" 
     } 

    end 

    # You could also use Rainbows! instead of Thin. 
    # Any EM based Rack handler should do. 
    App.run!({:port => 3000}) # <-- Changed this line from Thin.start to App.run! 
end 
+0

To działa dobrze . Jedno pytanie: w jaki sposób zdarzenia gniazd EventMachine mogą uzyskać dostęp do informacji o sesji w celu uwierzytelnienia, że ​​zdarzenia pochodzą od prawidłowo uwierzytelnionego użytkownika? –

+0

Wykreśliłem to zgodnie z moim komentarzem do odpowiedzi @Konstanti Haase, jako nowe pytanie - patrz http://stackoverflow.com/questions/16312024/how-to-decode-a-cookie-from-the-header- of-a-websocket-connection-handshake-rub –

7

FYI, można również skorzystać z EventMachine Padrino aplikacje (jak są podzbiory Sinatra aplikacjach):

require 'rubygems' 
require 'eventmachine' 
require 'padrino-core' 
require 'thin' 
require ::File.dirname(__FILE__) + '/config/boot.rb' 

EM.run do 
    Thin::Server.start Padrino.application, '0.0.0.0', 3000 
end 

Wiwaty, Mike

17

Natknąłem na ten projekt gitubowy websocket-rack, który jest w zasadzie rozszerzonym numerem katalogowym em-websocket i faktycznie sprawił, że działał ładnie obok siebie z Siną aplikacja tra. Oto mój config.ru:

require 'rubygems' 
require 'rack/websocket' 
require 'sinatra/base' 

class WebSocketApp < Rack::WebSocket::Application 
    # ... 
end 

class SinatraApp < Sinatra::Base 
    # ... 
end 

map '/ws' do 
    run WebSocketApp.new 
end 

map '/' do 
    run SinatraApp 
end 

Miłej zabawy!
Colin

+0

Colin - dla jasności, to jest w twoim pliku config.ru? – wchrisjohnson

+2

Dosłownie mówi "Oto moja konfiguracja.ru: "Tak więc myślę" Tak "jest odpowiedzią :) –

11

Używam sinatra-websocket. Pozwala to na uruchamianie serwera WebSocket w tym samym procesie i na tym samym porcie, co Sinatra.

Nota prawna: Jestem opiekunem.

require 'sinatra' 
require 'sinatra-websocket' 

set :server, 'thin' 
set :sockets, [] 

get '/' do 
    if !request.websocket? 
    erb :index 
    else 
    request.websocket do |ws| 
     ws.onopen do 
     ws.send("Hello World!") 
     settings.sockets << ws 
     end 
     ws.onmessage do |msg| 
     EM.next_tick { settings.sockets.each{|s| s.send(msg) } } 
     end 
     ws.onclose do 
     warn("websocket closed") 
     settings.sockets.delete(ws) 
     end 
    end 
    end 
end 

__END__ 
@@ index 
<html> 
    <body> 
    <h1>Simple Echo & Chat Server</h1> 
    <form id="form"> 
     <input type="text" id="input" value="send a message"></input> 
    </form> 
    <div id="msgs"></div> 
    </body> 

    <script type="text/javascript"> 
    window.onload = function(){ 
     (function(){ 
     var show = function(el){ 
      return function(msg){ el.innerHTML = msg + '<br />' + el.innerHTML; } 
     }(document.getElementById('msgs')); 

     var ws  = new WebSocket('ws://' + window.location.host + window.location.pathname); 
     ws.onopen = function() { show('websocket opened'); }; 
     ws.onclose = function() { show('websocket closed'); } 
     ws.onmessage = function(m) { show('websocket message: ' + m.data); }; 

     var sender = function(f){ 
      var input  = document.getElementById('input'); 
      input.onclick = function(){ input.value = "" }; 
      f.onsubmit = function(){ 
      ws.send(input.value); 
      input.value = "send a message"; 
      return false; 
      } 
     }(document.getElementById('form')); 
     })(); 
    } 
    </script> 
</html> 
+0

..To jest najszybszy sposób na wykorzystanie websocket z sinatrą (w moich oczach), czy mogę zapytać, jakie wady przynosi to podejście w porównaniu do używania 'em-websocket' , podklasy Sinatra :: Base, i "ręcznie" podłączenie do pętli zdarzeń? –

+0

również może ktoś dać krótkie wyjaśnienie, dlaczego jest tutaj "next_tick"? –

+0

@@ simulacre - Wszelkie pomysły, jak to działa na obciążenie Z powyższego przykładu, każdy proces Sinatry miałby wtedy swoją własną tablicę "settings.sockets", która przekształciłaby proces w stanowy? – rebnoob