Sinatra, индикатор выполнения в форме загрузки

Я разрабатываю приложение Sinatra, состоящее из формы загрузки, с индикатором выполнения, показывающим, сколько загрузки было завершено. Процесс, описанный ryan dahl, выглядит следующим образом:

Графики выполнения HTTP-загрузки довольно запутаны - они обычно включают процесс, выполняющийся на сервере, отслеживающий размер временного файла, который пишет HTTP-сервер, а затем на стороне клиента вызов AJAX выполняется каждые пару секунд до сервер во время загрузки, чтобы запросить ход загрузки.

Каждая загрузка имеет случайный session-id, и для отслеживания связи я использую class variable в своем приложении (я знаю, это ужасно - если у вас есть лучшие идеи, скажите, пожалуйста)

configure do
  @@assoc = {}
end

У меня есть маршрут POST для загрузки и GET один для опроса AJAX. Внутри маршрута POST я сохраняю ассоциацию session-id, Tempfile и общий размер.

post '/files' do
  tmp = params[:file][:tempfile]
  # from here on, @@assoc[@sid] should have a value, even in other routes
  @@assoc[@sid] = { :file => tmp, :size => env['CONTENT_LENGTH'] } 
  File.open("#{options.filesdir}/#{filename}", 'w+') do |file|
    file << tmp.read
  end
end 

В маршруте GET я рассчитываю процент, исходя из текущего размера Tempfile:

get '/status/:sid' do
  h = @@assoc[params[:sid]]
  unless h.nil?
    percentage = (h[:file].size / h[:size].to_f) * 100 
    "#{percentage}%"
  else
    "0%"
  end 
end

Проблема заключается в том, что до тех пор, пока запрос POST не завершится (т.е. после того, как он прочитал все Tempfile), h.nil? возвращает true, что на самом деле не имеет смысла, ve только присвоил @@assoc[@sid] значение в другом маршруте.

Итак, что мне здесь не хватает?

EDIT: Я пробовал

  • set :reload, false
  • set :environment, :production
  • config { @@assoc ||= {} }
  • Я также пытался бросить реляционный db на нем (SQLite с DataMapper)

Ни работали.

Ответ 1

Я думаю, что у меня проблема:

tmp = params[:file][:tempfile] не возвращается, пока файл не будет полностью получен.

Ответ 2

@@assoc[@sid] = { :file => tmp, :size => env['CONTENT_LENGTH'] }

должен быть

@@assoc[params[:sid]] = { :file => tmp, :size => env['CONTENT_LENGTH'] }