2011-10-09 27 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