2011-10-09 40 views
2

我有以下代碼將查詢某個字符串的Twitter流API。當我用不同的查詢打開兩個標籤時,它們都起作用。但是,當我停止其中一個選項卡時,另一個選項卡停止接收任何數據,並且服務器停止處理該流。我怎樣才能解決這個問題?與sinatra一起使用eventmachine時,如何關閉一個http連接而不關閉它們?

require 'sinatra' 
require 'eventmachine' 
require 'em-http' 
require 'json' 
require 'sinatra/streaming' 

enable :logging, :dump_errors, :raise_errors 

get '/test/:query' do 
    q = params[:query] 
    the = 'him' 
    url = "https://stream.twitter.com/1/statuses/filter.json?track=#{q}" 
    stream(:keep_open) do |out| 
    http = EM::HttpRequest.new(url) 
    s = http.get :head => { 'Authorization' => [ 'USERNAME', 'PASSWORD' ] } 
    out.callback do 
     puts "callback" 
     http.conn.close_connection 
    end 
    out.errback do 
     puts "errback" 
     http.conn.close_connection 
    end 
    buffer = "" 
    s.stream do |chunk| 
     puts "what" 
     buffer += chunk 
     while line = buffer.slice!(/.+\r?\n/) 
     tweet = JSON.parse(line) 
     unless tweet.length == 0 or tweet['user'].nil? or out.closed? 
      out << "<p><b>#{tweet['user']['screen_name']}</b>: #{tweet['text']}</p>" 
     end 
     end 
    end 
    end 
end 

回答

3

問題是,一旦您打開第二個連接,Twitter將關閉一個連接。嘗試在兩個終端上同時運行curl https://USER:[email protected]/1/statuses/filter.json?track=bar

此外,雖然試圖找出什麼是錯的,我做了一個相當小的重構來提高可讀性:

require 'sinatra' 
require 'sinatra/streaming' 
require 'eventmachine' 
require 'em-http' 
require 'json' 

enable :logging, :dump_errors, :raise_errors 
template(:tweet) { "<p><b><%= @tweet['user']['screen_name'] %></b>: <%= @tweet['text'] %></p>" } 

get '/test/:query' do |q| 
    stream(:keep_open) do |out| 
    http = EM::HttpRequest.new("https://stream.twitter.com/1/statuses/filter.json?track=#{q}") 

    EM.next_tick do 
     s = http.get :head => { 'Authorization' => ENV.values_at('USERNAME', 'PASSWORD') } 

     s.callback { out.close } 
     out.callback { s.close } 

     s.errback { out.close } 
     out.errback { s.close } 

     buffer = "" 
     s.stream do |chunk| 
     buffer << chunk 
     while line = buffer.slice!(/.+\r?\n/) 
      break if out.closed? 
      @tweet = JSON.parse(line) 
      out << erb(:tweet) if @tweet.length > 0 and @tweet['user'] 
     end 
     end 
    end 
    end 
end