-
-
Save rkh/1476463 to your computer and use it in GitHub Desktop.
# coding: utf-8 | |
require 'sinatra' | |
set server: 'thin', connections: [] | |
get '/' do | |
halt erb(:login) unless params[:user] | |
erb :chat, locals: { user: params[:user].gsub(/\W/, '') } | |
end | |
get '/stream', provides: 'text/event-stream' do | |
stream :keep_open do |out| | |
settings.connections << out | |
out.callback { settings.connections.delete(out) } | |
end | |
end | |
post '/' do | |
settings.connections.each { |out| out << "data: #{params[:msg]}\n\n" } | |
204 # response without entity body | |
end | |
__END__ | |
@@ layout | |
<html> | |
<head> | |
<title>Super Simple Chat with Sinatra</title> | |
<meta charset="utf-8" /> | |
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script> | |
</head> | |
<body><%= yield %></body> | |
</html> | |
@@ login | |
<form action='/'> | |
<label for='user'>User Name:</label> | |
<input name='user' value='' /> | |
<input type='submit' value="GO!" /> | |
</form> | |
@@ chat | |
<pre id='chat'></pre> | |
<script> | |
// reading | |
var es = new EventSource('/stream'); | |
es.onmessage = function(e) { $('#chat').append(e.data + "\n") }; | |
// writing | |
$("form").live("submit", function(e) { | |
$.post('/', {msg: "<%= user %>: " + $('#msg').val()}); | |
$('#msg').val(''); $('#msg').focus(); | |
e.preventDefault(); | |
}); | |
</script> | |
<form> | |
<input id='msg' placeholder='type message here...' /> | |
</form> |
(Note: I have deleted my previous comment, since that problem was either in the response body format, or in Sinatra version not supporting routing params in stream.)
I am trying to run the example and have some problems with :keep_open
and #callback
(I use Sinatra 1.3.2 and browse with Chrome 16):
- the connection is closed in 30-60 sec unless one sets a periodic timer as suggested by Konstantin elsewhere
- callback never fires (e.g. after page reload), and therefore the number of connections is growing
Can you replicate it? Is it possible to fix these issues somehow? WebSockets work seamlessly in this respect...
get '/stream', provides: 'text/event-stream' do
stream :keep_open do |out|
EventMachine::PeriodicTimer.new(20) { out << "data: \n\n" } # added
settings.connections << out
puts settings.connections.count # added
out.callback { puts 'closed'; settings.connections.delete(out) } # modified
end
end
var es = new EventSource('/stream');
es.onmessage = function(e) { if (e.data != '') $('#chat').append(e.data + "\n") }; // modified
Update:
This was a bug sinatra/sinatra#446
Lovely example, works a charm and nice and simple thanks!
I just started implementing Sinatra Streaming into my app. Going great so far. What I need to figure out is how to stream changes for an account only to users on that account and not everyone. Can anyone point me in the right direction or link to some sample code?
Great example.
How do I send messages from outside the Sinatra endpoints? I have an async event handler that listens for messages from another server, and I want to be able to forward a message on one of the Sinatra connections. I have stored the connection objects in a class Array and retrieve the connection and append the message on it (<<), but I assume I need to send the response by using something similar to "204", but how do I do that from outside the SSE endpoint (get {})?
Thanks!
It seems like it has to do with the fact that I have mounted the Sinatra app inside a Rails app. I get it to work when running the Sinatra app by itself, but when running it inside the Rails app the connection seems to be dropped because the browser is reconnecting continuously and therefore I won't be able to stream messages from my message handler.
Is there anything I need to configure in Rails for this to work?
The Rails issue is well known, dunno what's breaking here, I think they wrap the body object somewhere and the errback
/callback
methods get lost on the way. Solution for now is to mount it in the config.ru
rather than your routes.rb
.
Yeah, I tried adding the Sinatra app as a Rails middleware and it worked. Cheers.
pretty good.
a nice alternative with websockets, with javascript polyfills
Just what I needed! Thanks a lot.
Nice,
Since no specific version of jQuery is requested, it doesn't work anymore on the Heroku demo.
Because "live" was removed.
It works with this revision
You probably knew this as it was a year ago, but just in case...
rkj, do you have padrino version?
How many clients would this reasonable support, using say, thin?
Change line 29 to <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8/jquery.min.js"></script>
if you have trouble getting it to run. There was an api change in JQuery 1.9.
As @multiholle pointed out, JQuery changed.
If you want to use the latest version of jquery, the line:
$("form").live("submit", function(e) {
can be changed to:
$("body").on("submit", "form", function(e) {
Very cool! Thanks for the simple and helpful snippet. =]