The Artima Developer Community
Sponsored Link

Ruby Buzz Forum
The Mongrel Comet

0 replies on 1 page.

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 0 replies on 1 page
Christopher Cyll

Posts: 49
Nickname: topher
Registered: Jan, 2006

Topher Cyll is Rubyist and writer in Portland, Oregon.
The Mongrel Comet Posted: Aug 10, 2006 12:01 AM
Reply to this message Reply

This post originated from an RSS feed registered with Ruby Buzz by Christopher Cyll.
Original Post: The Mongrel Comet
Feed Title: Topher Cyll
Feed URL: http://feeds.feedburner.com/cyll
Feed Description: I'm not too worried about it. Ruby and programming languages.
Latest Ruby Buzz Posts
Latest Ruby Buzz Posts by Christopher Cyll
Latest Posts From Topher Cyll

Advertisement
Comet is a javascript technology used to receive events without AJAX polling. You can read about Comet on Wikipedia.

Mongrel is an excellent HTTP server for Ruby. Have a look at its cute dog.

While I was playing around with a Ruby based DHTML turn based strategy game a few weeks ago, I found myself struggling with latency. I was using an AJAX polling mechanism, and with all the game logic on the server side, things felt laggy. There were any number of options I could have tried. And, in fact, in the end, I just ignored the problem.

However, in the process I read about Comet and began to wonder how hard it would be to add it to Mongrel.

It turned out to be suprisingly easy... after a fashion.

COMET_FORMAT = "HTTP/1.1 %d %s\r\nContent-Type: %s\r\nTransfer-Encoding: chunke\
d\r\nConnection: close\r\n".freeze

class HttpResponse
  def comet(type,  status=200)
    write(Const::COMET_FORMAT % [status, HTTP_STATUS_CODES[status], type])
    write("\r\n")
    return HttpComet.new(self)
  end
end

Above, you can see the first thing we do is add a comet() method to our response object, this returns an object we can stream our data out through. We'd use the HttpComet object like this, writing each integer up to 100 to the connection:

class ExampleCometHandler < Mongrel::HttpHandler
  def process(request, response)
    comet = response.comet("text/plain")
    (0..100).each do |i|
      comet.write("#{i}");
      sleep 1
    end
    comet.close
  end
end

The code that makes this all work lives inside HttpComet. It uses "chunked" HTTP transfer to send portions of the data along at a time.

class HttpComet
  def initialize(response)
    @response = response
  end

  def write(data)
    size = data.size
    @response.write(sprintf("%x;\r\n", size))
    @response.write(data)
    @response.write("\r\n")
    @response.flush
  end

  def close
    @response.write("0;\r\n")
  end
end

Each chunk starts with a number of bytes in hex, followed by an \r\n, then the payload. A chunk of size 0 indicates the end of the file. And that's all there is.

Now, there's one problem. The way I'm doing this has the side effect that only one user can be Comet streaming from any particular handler instance. Registering another instance of the same handler at a different URL and using some kind of redirect to get each user to their own URL and handler can work around this, but it's ugly as sin.

But hey, I learned about HTTP chunked mode!

[Code Available Here]

Update: Oh, it's worth mentioning, getting events to actually trigger on receipt for all platforms is tricky, so instead of just sending data, often Javascript is loaded into an iframe. You can see an example of this in the source.

Read: The Mongrel Comet

Topic: d3 not DDD Previous Topic   Next Topic Topic: Easily redistribute those beautifully crafted Ruby apps with RubyScript2Exe

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use