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() |