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