При использовании eventmachine с sinatra, как я могу закрыть одно http-соединение, не закрывая их все? - PullRequest
2 голосов
/ 09 октября 2011

У меня есть следующий код, который запросит API потоковой передачи Twitter для определенной строки. Когда я открываю две вкладки с разными запросами, они обе работают. Однако, когда я останавливаю одну из вкладок, другая вкладка перестает получать какие-либо данные, и сервер прекращает обработку потока. Как я могу это исправить?

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

1 Ответ

3 голосов
/ 10 октября 2011

Проблема в том, что Twitter закрывает одно соединение, когда вы открываете второе. Попробуйте запустить curl <a href="https://USER:PASSWORD@stream.twitter.com/1/statuses/filter.json?track=bar" rel="nofollow">https://USER:PASSWORD@stream.twitter.com/1/statuses/filter.json?track=bar</a> на двух терминалах одновременно.

Кроме того, пытаясь выяснить, что не так, я провел довольно небольшой рефакторинг для улучшения читабельности:

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
...