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
-~----------~----~----~----~------~----~------~--~---

Reply via email to