Any success with Sinatra working together with EventMachine WebSockets?

前端 未结 5 2174
陌清茗
陌清茗 2020-12-07 10:02

I have been using Sinatra for sometime now and I would like to add some realtime features to my web-app by pushing the data via websockets.

I have successfully used

相关标签:
5条回答
  • 2020-12-07 10:21

    Did not try it, but should not be too hard:

    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
    

    Also, Cramp has a websocket implementation that works directly with Thin/Rainbows! you might be able to extract, so you won't even need to run the server on another port.

    0 讨论(0)
  • 2020-12-07 10:37

    I've been using sinatra-websocket. It let's you run the websocket server in the same process and on the same port as Sinatra.

    Disclaimer: I'm the maintainer.

    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 讨论(0)
  • 2020-12-07 10:41

    I stumbled onto this websocket-rack github project which is basically a rackified em-websocket and actually got it to work nicely side-by-side with a Sinatra app. Here's my 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
    

    Have fun!
    Colin

    0 讨论(0)
  • 2020-12-07 10:45

    Thanks Konstantin... that worked! I had to tweak your code slightly. I added comments where I changed it.

    -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 讨论(0)
  • 2020-12-07 10:47

    FYI, you can also use Padrino apps with EventMachine (as they are subsets of Sinatra apps):

    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
    

    Cheers, Mike

    0 讨论(0)
提交回复
热议问题