| Index: third_party/pyftpdlib/demo/throttled_ftpd.py | 
| =================================================================== | 
| --- third_party/pyftpdlib/demo/throttled_ftpd.py	(revision 0) | 
| +++ third_party/pyftpdlib/demo/throttled_ftpd.py	(revision 0) | 
| @@ -0,0 +1,89 @@ | 
| +#!/usr/bin/env python | 
| +# throttled_ftpd.py | 
| + | 
| +"""ftpd supporting bandwidth throttling capabilities for data transfer. | 
| +""" | 
| + | 
| +import os | 
| +import time | 
| +import asyncore | 
| + | 
| +from pyftpdlib import ftpserver | 
| + | 
| + | 
| +class ThrottledDTPHandler(ftpserver.DTPHandler): | 
| +    """A DTPHandler which wraps sending and receiving in a data counter | 
| +    and temporarily sleeps the channel so that you burst to no more than | 
| +    x Kb/sec average. | 
| +    """ | 
| + | 
| +    # maximum number of bytes to transmit in a second (0 == no limit) | 
| +    read_limit = 0 | 
| +    write_limit = 0 | 
| + | 
| +    def __init__(self, sock_obj, cmd_channel): | 
| +        ftpserver.DTPHandler.__init__(self, sock_obj, cmd_channel) | 
| +        self._timenext = 0 | 
| +        self._datacount = 0 | 
| +        self._sleeping = False | 
| +        self._throttler = None | 
| + | 
| +    def readable(self): | 
| +        return not self._sleeping and ftpserver.DTPHandler.readable(self) | 
| + | 
| +    def writable(self): | 
| +        return not self._sleeping and ftpserver.DTPHandler.writable(self) | 
| + | 
| +    def recv(self, buffer_size): | 
| +        chunk = asyncore.dispatcher.recv(self, buffer_size) | 
| +        if self.read_limit: | 
| +            self.throttle_bandwidth(len(chunk), self.read_limit) | 
| +        return chunk | 
| + | 
| +    def send(self, data): | 
| +        num_sent = asyncore.dispatcher.send(self, data) | 
| +        if self.write_limit: | 
| +            self.throttle_bandwidth(num_sent, self.write_limit) | 
| +        return num_sent | 
| + | 
| +    def throttle_bandwidth(self, len_chunk, max_speed): | 
| +        """A method which counts data transmitted so that you burst to | 
| +        no more than x Kb/sec average. | 
| +        """ | 
| +        self._datacount += len_chunk | 
| +        if self._datacount >= max_speed: | 
| +            self._datacount = 0 | 
| +            now = time.time() | 
| +            sleepfor = self._timenext - now | 
| +            if sleepfor > 0: | 
| +                # we've passed bandwidth limits | 
| +                def unsleep(): | 
| +                    self._sleeping = False | 
| +                self._sleeping = True | 
| +                self._throttler = ftpserver.CallLater(sleepfor * 2, unsleep) | 
| +            self._timenext = now + 1 | 
| + | 
| +    def close(self): | 
| +        if self._throttler is not None and not self._throttler.cancelled: | 
| +            self._throttler.cancel() | 
| +        ftpserver.DTPHandler.close(self) | 
| + | 
| + | 
| +if __name__ == '__main__': | 
| +    authorizer = ftpserver.DummyAuthorizer() | 
| +    authorizer.add_user('user', '12345', os.getcwd(), perm='elradfmw') | 
| +    authorizer.add_anonymous(os.getcwd()) | 
| + | 
| +    # use the modified DTPHandler class and set a speed limit for both | 
| +    # sending and receiving | 
| +    dtp_handler = ThrottledDTPHandler | 
| +    dtp_handler.read_limit = 30072  # 30 Kb/sec (30 * 1024) | 
| +    dtp_handler.write_limit = 30072  # 30 Kb/sec (30 * 1024) | 
| + | 
| +    ftp_handler = ftpserver.FTPHandler | 
| +    ftp_handler.authorizer = authorizer | 
| +    # have the ftp handler use the different dtp handler | 
| +    ftp_handler.dtp_handler = dtp_handler | 
| + | 
| +    ftpd = ftpserver.FTPServer(('', 21), ftp_handler) | 
| +    ftpd.serve_forever() | 
|  |