Sinatra, progress bar in upload form
Asked Answered
U

2

10

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.

Unquiet answered 22/6, 2010 at 18:21 Comment(1)
The @@assoc[@sid] = {... line is missing a } at the end.Imagery
U
4

I think i got what the problem is:

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

Unquiet answered 22/6, 2010 at 22:50 Comment(0)
I
1
@@assoc[@sid] = { :file => tmp, :size => env['CONTENT_LENGTH'] }

should be

@@assoc[params[:sid]] = { :file => tmp, :size => env['CONTENT_LENGTH'] }
Imagery answered 22/6, 2010 at 18:37 Comment(1)
yeah, it's a typo in the question, it's ok in the real app. thanks anyway for reporting.Unquiet

© 2022 - 2024 — McMap. All rights reserved.