неділя, 29 квітня 2012 р.

Стрімінг в Sinatra

Починаючи з 1.3.0, Sinatra підтримує стрімінг(streaming API). В інтернеті ви точно стикалися з його реалізацією. Наприклад стрічка Twitter чи новини ВКонтакте.

Іноді потрібно почати відправляти дані клієнту прямо в процесі генерування частин цих даних. В особливих випадках потрібно постійно відправляти дані до тих пір, поки клієнт не закриє з'єднання. Ви можете використовувати метод stream замість написання власних "обгорток".

Почнемо з класичного прикладу з документації Sinatra:
get '/' do
  stream do |out|
    out << "It's gonna be legen -\n"
    sleep 0.5
    out << " (wait for it) \n"
    sleep 1
    out << "- dary!\n"
  end
end

Якщо сервер не підтримує стрімінг (наприклад, WEBRick), то всі дані будуть відправлені за один раз відразу після того, як блок, переданий в stream, завершиться.


Це дозволяє вам реалізувати потокові API, Server-Sent Events, і може служити основою для WebSockets. Також такий підхід можна використовувати для збільшення продуктивності у випадку, коли якась частина контенту залежить від повільного ресурсу.

І що дійсно цікаво: якщо ви працюєте на потоковому(evented) сервері, наприклад Thin, ви можете тримати з'єднання відкритим і легко реалізувати обмін повідомленнями.
Якщо метод stream використовується з параметром keep_open, то він не буде викликати close в об'єкта потоку, що дозволить вам закрити його пізніше в будь-якому іншому місці.

Приклад простого чату:
https://gist.github.com/2551354
# -*- encoding: utf-8 -*-
require 'sinatra'
require 'slim'
set :server, 'thin'
connections = []
get '/' do
halt slim(:login) unless params[:user]
slim :chat, :locals => { :user => params[:user].gsub(/\W/, '') }
end
get '/stream', :provides => 'text/event-stream' do
stream :keep_open do |out|
connections << out
out.callback { connections.delete(out) }
end
end
post '/' do
connections.each { |out| out << "data: #{params[:msg]}\n\n" }
# http://ru.wikipedia.org/wiki/Список_кодов_состояния_HTTP#204
204 # response without entity body
end
__END__
@@ layout
html
head
title Simple Chat with Sinatra
meta charset="utf-8"
script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"
body
== yield
@@ login
form action='/'
label for='user' User Name:
input name='user' value=''
input type='submit' value="GO!"
@@ chat
form
input id='msg' placeholder='type message here...'
pre id='chat'
javascript:
// 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();
});
view raw sinatra_chat.rb hosted with ❤ by GitHub

Немає коментарів: