Search code examples
javascriptrubyajaxwebsocketthin

Using websocket with Thin


I am trying to use websocket on Thin server. The following code is an attempt to run a clock that updates the time on the web page every 0.1 second.

  • PAGE is the content of the initial page to be rendered.
  • The Thin server is initiated with serve and session methods.
  • Websocket is initiated by the websocket method.
  • tick_every is a utility function that calls a block at the right timing for every time interval given.

Code:

require "rack"
require "thin"
require "em-websocket"

PAGE = <<_
<html>
<body><div id="output"></div></body>
<script>
    window.addEventListener("load", init, false);
    function init(){
        websocket = new WebSocket("ws://localhost:4000");
        websocket.onmessage = function(evt){
            document.getElementById("output").innerHTML = evt.data;
        };
    }
</script>
<div id="output"></div>
</html>
_

def serve
    Rack::Handler::Thin.run(Rack::Builder.new do
        map("/"){run(->env{session(env)})}
    end, Port: 3000)
end
def session env
        websocket(env["SERVER_NAME"])
        [200, {}, [PAGE]]
end
def websocket host
    EM.run do
        EM::WebSocket.run(host: host, port: 4000) do |ws|
            ws.onopen do
                tick_every(0.1){|t| ws.send "The time now since epoch in sec is #{t}"}
            end
        end
    end
end
def tick_every sec, &pr
    Thread.new do loop do
        t = Time.now.to_f            # present time in micro seconds
        frac = t.modulo(sec.to_f)    # fractional (decimal) part of it w.r.t. `sec`
        pr.call((t - frac).round(6)) # calls the block, passing the present time with precision of `sec`
        sleep(sec - frac)            # wait for the next flat `sec`
    end end
end

serve

When I run this and open the webpage at localhost:3000, websocket returns an error message in the console:

!! Unexpected error while processing request: no acceptor (port is in use or requires root privileges)

and shows the initial time on the web page, but does not update it for thirty seconds (not sure, but this seems constant, which may have some meaning), and after that, it starts to update the clock every 0.1 second.

  • What is causing the error message from websocket?
  • Why does it pause for thirty seconds and then start working?
  • Is this a proper way to combine ajax and websocket?
  • How can I fix these problems?

Solution

  • The problem turned out to be that, the browser was requesting a favicon, which I had not set up. Probably, it waited till timeout, which is perhaps thirty seconds, then started to work after that. The error came from favicon request.