Search code examples
rubywebsocketsinatra

Sinatra pass data from TCP to websockets


I am attempting to use Sinatra to listen to a custom HTTP method. Whatever data is received from there, is passed through websocket to n number of clients, in real-time.

This is the progress -

  1. I have been able to make Sinatra listen to the custom HTTP method, NOTIFY.
  2. I also have a websocket server running.
  3. But I can't figure out the last part, passing the data from NOTIFY as and when received to the websocket clients. How to do this?

Ruby app.rb

require 'sinatra'
require 'sinatra-websocket'

configure do
  class << Sinatra::Base
    def notify(path, opts={}, &block)
      route 'NOTIFY', path, opts, &block
    end
  end
  Sinatra::Delegator.delegate :notify
end

set :server, 'thin'
set :sockets, []
set :bind, '0.0.0.0'
enable :sessions # For some reason sessions don't work. Relying on class variable.



notify '/' do   
    @json = request.body.read    
    session[:order] = @json
    @@pass = session[:order] # Saved in class variable. Hacky?
    puts "NOTIFY"
    puts "is session[:order] nil? #{session[:order].nil?}" # returns false
    puts "END NOTIFY"
end    

get '/' do
  if !request.websocket?
    puts @@pass # prints NOTIFY data successfully

    puts "GETS"
    puts "is session[:order] nil? #{session[:order].nil?}" # returns true. Session dont work
    puts "END GETS"

    @new = @@pass
    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) } }
        ws.send(@@pass) # this will send on each message. Not real-time
      end
      ws.onclose do
        warn("websocket closed")
        settings.sockets.delete(ws)
      end
    end
  end
end    

__END__

Inline ERB Index

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


  <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);
        console.log(ws);
        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>
    </body>
</html>

Is there any other industrial way for a robust data transmission in this manner?


Solution

  • I found this to be difficult to interface. Instead, a compartmentalized approach does the job.

    Starting a websocket server separately and independently, which the Sinatra server communicates as a client, a short lived one, on every incoming TCP request.

    The websocket server broadcasts this incoming message to all other connected clients.