after read over this "thread [web2py:23034] Upload progress" http://www.mail-archive.com/[email protected]/msg13111.html
I have looks around how other web framework done this, in pylons's way, this require a WSGI middleware and URLmap, unfortunately URLmap is impossible for web2py, and wrap middleware like "gp.fileupload" or insert filer in cherrypy also require lot's of hack, in django's way, it hooks handler at input chain, which web2py doesn't have, but it just store the upload progress in cache, which is possible for web2py, so I made the patch to proof this works I just made a proof of concept to provide upload progress, part of code and idea taken from django snippets with some modification http://www.djangosnippets.org/snippets/678 http://www.djangosnippets.org/snippets/679/ here is the major part -------------------------------------------------------------------------------- --- web2py-orig/main.py 2009-09-22 09:07:52.000000000 +0800 +++ web2py/main.py 2009-10-07 16:07:55.000000000 +0800 @@ -335,6 +335,51 @@ if request.env.content_length: request.body = tempfile.TemporaryFile() + def copystream( + src, + dest, + size, + chunk_size=10 ** 5, + ): + """ + original from fileutils, + this is a hacking for progress upload status, + """ + import time + progressCache = True + try: + cache_key = 'X-Progress-ID:'+request.get_vars ['X-Progress-ID'] + except KeyError: + progressCache = False + if progressCache: + from cache import Cache + cache = Cache(request) + cache.ram(cache_key+':length', lambda: size, 0) + cache.ram(cache_key+':uploaded', lambda: 0, 0) + while size > 0: + if size < chunk_size: + data = src.read(size) + if progressCache: + cache.ram.increment(cache_key +':uploaded', size) + else: + data = src.read(chunk_size) + if progressCache: + cache.ram.increment(cache_key +':uploaded', chunk_size) + length = len(data) + if length > size: + (data, length) = (data[:size], size) + size -= length + if length == 0: + break + dest.write(data) + if length < chunk_size: + break + dest.seek(0) + if progressCache: + cache.ram(cache_key+':length', None) + cache.ram(cache_key+':uploaded', None) + return copystream(request.env.wsgi_input, request.body, int(request.env.content_length)) else: -------------------------------------------------------------------------------- maybe just wrap wsgi_input will make it pretty, next is how to use it, at controller, just require a function to respond json -------------------------------------------------------------------------------- def post(): #I need a from, give me give me return dict(form=crud.create(db.foo_table)) @service.jsonrpc def progress_report_by_id(): cache_key = 'X-Progress-ID:'+request.get_vars['X-Progress-ID'] return dict( length=cache.ram(cache_key+':length', lambda: 0, None), uploaded=cache.ram(cache_key+':uploaded', lambda: 0, None), ) -------------------------------------------------------------------------------- at view you can do whatever you want, this one is post.html for post function up there, or just take javascript snippet part, watch out "var progress_url", you have to modify this to match your app/controller/function somewhere -------------------------------------------------------------------------------- {{extend 'layout.html'}} <script type="text/javascript"> // Generate 32 char random uuid function gen_uuid() { var uuid = "" for (var i=0; i < 32; i++) { uuid += Math.floor(Math.random() * 16).toString(16); } return uuid } // Add upload progress for multipart forms. $(function() { $('form[enctype=multipart/form-data]').submit(function(){ // Prevent multiple submits if ($.data(this, 'submitted')) return false; var freq = 1000; // freqency of update in ms var uuid = gen_uuid(); // id for this upload so we can fetch progress info. var progress_url = /poc/default/ progress_report_by_id.json'; // ajax view serving progress info // Append X-Progress-ID uuid form action this.action += (this.action.indexOf('?') == -1 ? '?' : '&') + 'X-Progress-ID=' + uuid; var $progress = $('<div id="upload-progress" class="upload- progress"></div>'). insertAfter($('input[type=submit]')).append('<div class="progress-container"><span class="progress-info">uploading 0%</ span><div class="progress-bar"></div></div>'); $('input[type=submit]').remove() // progress bar position /* $progress.css({ position: ($.browser.msie && $.browser.version < 7 )? 'absolute' : 'fixed', left: '50%', marginLeft: 0-($progress.width()/2), bottom: '20%' }).show(); */ $progress.find('.progress-bar').height('1em').width(0).css ("background-color", "red"); // Update progress bar function update_progress_info() { $progress.show(); $.getJSON(progress_url, {'X-Progress-ID': uuid}, function (data, status){ if (data) { var progress = parseInt(data.uploaded) / parseInt (data.length); var width = $progress.find('.progress- container').width() var progress_width = width * progress; $progress.find('.progress-bar').width (progress_width); $progress.find('.progress-info').text('uploading ' + progress*100 + '%'); } window.setTimeout(update_progress_info, freq); }); }; window.setTimeout(update_progress_info, freq); $.data(this, 'submitted', true); // mark form as submitted. }); }); </script> {{=BEAUTIFY(response._vars)}} -------------------------------------------------------------------------------- that's all, hope one developer can pretty this implementation and migrate it into the core and widget :) --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "web2py-users" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [email protected] For more options, visit this group at http://groups.google.com/group/web2py?hl=en -~----------~----~----~----~------~----~------~--~---

