37 votes

Avez-vous réussi à faire fonctionner Sinatra avec les WebSockets d'EventMachine ?

J'utilise Sinatra depuis un certain temps maintenant et je voudrais ajouter quelques fonctionnalités en temps réel à ma web-app en poussant les données via des websockets.

J'ai utilisé avec succès la gemme 'em-websocket' seule, mais je n'ai pas été capable d'écrire un fichier ruby qui a un serveur web sinatra ET un serveur web-socket.

J'ai essayé de faire tourner les méthodes run ! ou start ! dans des fils séparés, sans succès.

Quelqu'un a-t-il réussi à le faire fonctionner ?

Je veux les avoir dans le même fichier car je peux alors partager les variables entre les deux serveurs.

Merci !

27voto

Konstantin Haase Points 12089

Je n'ai pas essayé, mais ça ne devrait pas être trop difficile :

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

También, Crampe possède une implémentation websocket qui fonctionne directement avec Thin/Rainbows ! que vous pourriez extraire, de sorte que vous n'aurez même pas besoin d'exécuter le serveur sur un autre port.

20voto

Poul Points 1215

Merci Konstantin... ça a marché ! J'ai dû modifier légèrement votre code. J'ai ajouté des commentaires là où je l'ai modifié.

-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

17voto

Colin Surprenant Points 413

Je suis tombé sur ce websocket-rack projet github qui est fondamentalement un rackified em-websocket et j'ai réussi à la faire fonctionner côte à côte avec une application Sinatra. Voici mon 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

Amusez-vous bien !
Colin

12voto

simulacre Points 956

J'ai utilisé sinatra-websocket . Il vous permet d'exécuter le serveur websocket dans le même processus et sur le même port que Sinatra.

Clause de non-responsabilité : je suis le mainteneur.

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>

8voto

user546469 Points 71

Pour votre information, vous pouvez également utiliser les applications Padrino avec EventMachine (puisqu'elles sont des sous-ensembles des applications Sinatra) :

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

Santé, Mike

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X