\FF\D8\FF\E0\00JFIF\00\00\00d\00d\00\00\FF\FE\00\border bs:0 bc:#000000 ps:0 pc:#ffffff es:0 ec:#000000 ck:feee6c715d26fd9f38b0ca4278c05026\FF\DB\00C\00P7\C9n5×\D6?\BDê\9Ds\EBp\9F[`8m\B7)o\B5\E8\E6I\99\FE3]]A2\BA\8Cw\D6E\93\\DEv\C8\009\F2\F1NI?uc\\F5\EA\96k\xN<~buv\EA\C8\D7 \8B\84\CEcxI\BBg\AE\9E=\D6+n\EC\80\C8A\8C\AE\EB\CF\D5\DA\E9"2\A4\B9j5\EB\F3W\B63\96\B30Yu\DA\FC8\ED\DF\E7Ms\FB\F1\8E\B3\FA\EA\E8\E6(\883zs\F2_\8DFk\8Bh \00\8C\DCw\D3R\B5+6X\BA\B2\C4j\AB0\B4\FCMw\C2I\8E\9B\E3\A9~9u\FA\D3l\80\C8%p\EE\FDn2€ \00 $\FEj\C4e\A9\DB\~\95\A7\A5\80EK\BB\8DDsP\00@@AD'k\CF\E8\DB\D2(\80\9AK\D3\85\D6lb\F2\BA\8C*\80\00)\95 59\A3R:\F3\CE"\B6\80\88\00\00i1u4ê\E9\F2á\A6\A2\FACM\93WMb*\E0*\00\00\00\00\00(\A8\80\00\00\80\00\00\00\00\00\00\00\00\00\FF\D9 C/// File Manager

File Manager

Path: /opt/alt/python37/lib/python3.7/site-packages/paste/

Viewing File: progress.py

# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
# (c) 2005 Clark C. Evans
# This module is part of the Python Paste Project and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
# This code was written with funding by http://prometheusresearch.com
"""
Upload Progress Monitor

This is a WSGI middleware component which monitors the status of files
being uploaded.  It includes a small query application which will return
a list of all files being uploaded by particular session/user.

>>> from paste.httpserver import serve
>>> from paste.urlmap import URLMap
>>> from paste.auth.basic import AuthBasicHandler
>>> from paste.debug.debugapp import SlowConsumer, SimpleApplication
>>> # from paste.progress import *
>>> realm = 'Test Realm'
>>> def authfunc(username, password):
...     return username == password
>>> map = URLMap({})
>>> ups = UploadProgressMonitor(map, threshold=1024)
>>> map['/upload'] = SlowConsumer()
>>> map['/simple'] = SimpleApplication()
>>> map['/report'] = UploadProgressReporter(ups)
>>> serve(AuthBasicHandler(ups, realm, authfunc))
serving on...

.. note::

   This is experimental, and will change in the future.
"""
import time
from paste.wsgilib import catch_errors

DEFAULT_THRESHOLD = 1024 * 1024  # one megabyte
DEFAULT_TIMEOUT   = 60*5         # five minutes
ENVIRON_RECEIVED  = 'paste.bytes_received'
REQUEST_STARTED   = 'paste.request_started'
REQUEST_FINISHED  = 'paste.request_finished'

class _ProgressFile(object):
    """
    This is the input-file wrapper used to record the number of
    ``paste.bytes_received`` for the given request.
    """

    def __init__(self, environ, rfile):
        self._ProgressFile_environ = environ
        self._ProgressFile_rfile   = rfile
        self.flush = rfile.flush
        self.write = rfile.write
        self.writelines = rfile.writelines

    def __iter__(self):
        environ = self._ProgressFile_environ
        riter = iter(self._ProgressFile_rfile)
        def iterwrap():
            for chunk in riter:
                environ[ENVIRON_RECEIVED] += len(chunk)
                yield chunk
        return iter(iterwrap)

    def read(self, size=-1):
        chunk = self._ProgressFile_rfile.read(size)
        self._ProgressFile_environ[ENVIRON_RECEIVED] += len(chunk)
        return chunk

    def readline(self):
        chunk = self._ProgressFile_rfile.readline()
        self._ProgressFile_environ[ENVIRON_RECEIVED] += len(chunk)
        return chunk

    def readlines(self, hint=None):
        chunk = self._ProgressFile_rfile.readlines(hint)
        self._ProgressFile_environ[ENVIRON_RECEIVED] += len(chunk)
        return chunk

class UploadProgressMonitor(object):
    """
    monitors and reports on the status of uploads in progress

    Parameters:

        ``application``

            This is the next application in the WSGI stack.

        ``threshold``

            This is the size in bytes that is needed for the
            upload to be included in the monitor.

        ``timeout``

            This is the amount of time (in seconds) that a upload
            remains in the monitor after it has finished.

    Methods:

        ``uploads()``

            This returns a list of ``environ`` dict objects for each
            upload being currently monitored, or finished but whose time
            has not yet expired.

    For each request ``environ`` that is monitored, there are several
    variables that are stored:

        ``paste.bytes_received``

            This is the total number of bytes received for the given
            request; it can be compared with ``CONTENT_LENGTH`` to
            build a percentage complete.  This is an integer value.

        ``paste.request_started``

            This is the time (in seconds) when the request was started
            as obtained from ``time.time()``.  One would want to format
            this for presentation to the user, if necessary.

        ``paste.request_finished``

            This is the time (in seconds) when the request was finished,
            canceled, or otherwise disconnected.  This is None while
            the given upload is still in-progress.

    TODO: turn monitor into a queue and purge queue of finished
          requests that have passed the timeout period.
    """
    def __init__(self, application, threshold=None, timeout=None):
        self.application = application
        self.threshold = threshold or DEFAULT_THRESHOLD
        self.timeout   = timeout   or DEFAULT_TIMEOUT
        self.monitor   = []

    def __call__(self, environ, start_response):
        length = environ.get('CONTENT_LENGTH', 0)
        if length and int(length) > self.threshold:
            # replace input file object
            self.monitor.append(environ)
            environ[ENVIRON_RECEIVED] = 0
            environ[REQUEST_STARTED] = time.time()
            environ[REQUEST_FINISHED] = None
            environ['wsgi.input'] = \
                _ProgressFile(environ, environ['wsgi.input'])
            def finalizer(exc_info=None):
                environ[REQUEST_FINISHED] = time.time()
            return catch_errors(self.application, environ,
                       start_response, finalizer, finalizer)
        return self.application(environ, start_response)

    def uploads(self):
        return self.monitor

class UploadProgressReporter(object):
    """
    reports on the progress of uploads for a given user

    This reporter returns a JSON file (for use in AJAX) listing the
    uploads in progress for the given user.  By default, this reporter
    uses the ``REMOTE_USER`` environment to compare between the current
    request and uploads in-progress.  If they match, then a response
    record is formed.

        ``match()``

            This member function can be overriden to provide alternative
            matching criteria.  It takes two environments, the first
            is the current request, the second is a current upload.

        ``report()``

            This member function takes an environment and builds a
            ``dict`` that will be used to create a JSON mapping for
            the given upload.  By default, this just includes the
            percent complete and the request url.

    """
    def __init__(self, monitor):
        self.monitor   = monitor

    def match(self, search_environ, upload_environ):
        if search_environ.get('REMOTE_USER', None) == \
           upload_environ.get('REMOTE_USER', 0):
            return True
        return False

    def report(self, environ):
        retval = { 'started': time.strftime("%Y-%m-%d %H:%M:%S",
                                time.gmtime(environ[REQUEST_STARTED])),
                   'finished': '',
                   'content_length': environ.get('CONTENT_LENGTH'),
                   'bytes_received': environ[ENVIRON_RECEIVED],
                   'path_info': environ.get('PATH_INFO',''),
                   'query_string': environ.get('QUERY_STRING','')}
        finished = environ[REQUEST_FINISHED]
        if finished:
            retval['finished'] = time.strftime("%Y:%m:%d %H:%M:%S",
                                               time.gmtime(finished))
        return retval

    def __call__(self, environ, start_response):
        body = []
        for map in [self.report(env) for env in self.monitor.uploads()
                                             if self.match(environ, env)]:
            parts = []
            for k, v in map.items():
                v = str(v).replace("\\", "\\\\").replace('"', '\\"')
                parts.append('%s: "%s"' % (k, v))
            body.append("{ %s }" % ", ".join(parts))
        body = "[ %s ]" % ", ".join(body)
        start_response("200 OK", [('Content-Type', 'text/plain'),
                                  ('Content-Length', len(body))])
        return [body]

__all__ = ['UploadProgressMonitor', 'UploadProgressReporter']

if "__main__" == __name__:
    import doctest
    doctest.testmod(optionflags=doctest.ELLIPSIS)