Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sinatra, progress bar in upload form

I'm developing a Sinatra app that consists of an upload form, with a progress bar indicating how much of the upload has completed. The process, as described by ryan dahl, is the following:

HTTP upload progress bars are rather obfuscated- they typically involve a process running on the server keeping track of the size of the tempfile that the HTTP server is writing to, then on the client side an AJAX call is made every couple seconds to the server during the upload to ask for the progress of the upload.

Every upload has a random session-id, and to keep track of the association i employ a class variable in my app (i know, that's horrible -- if you've got better ideas, please tell me)

configure do
  @@assoc = {}
end

I have a POST route for the upload, and a GET one for the AJAX polling. Inside the POST route i save the association of session-id, Tempfile, and total size.

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 

In the GET route, i calculate the percentage based on the Tempfile's current size:

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

The problem is that until the POST request hasn't completed (i.e., after it has read all of the Tempfile) the h.nil? returns true, which doesn't really make sense as I've just assigned @@assoc[@sid] a value in the other route.

So, what am I missing here?

EDIT: I've tried

  • set :reload, false
  • set :environment, :production
  • config { @@assoc ||= {} }
  • I also tried throwing a relational db at it (SQLite with DataMapper)

Neither worked.

like image 646
asymmetric Avatar asked Jun 22 '10 18:06

asymmetric


2 Answers

I think i got what the problem is:

tmp = params[:file][:tempfile] doesn't return until the file has been fully received.

like image 107
asymmetric Avatar answered Nov 07 '22 04:11

asymmetric


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

should be

@@assoc[params[:sid]] = { :file => tmp, :size => env['CONTENT_LENGTH'] }
like image 32
Adrian Avatar answered Nov 07 '22 04:11

Adrian