diff --git a/client/djrandom_client/client.py b/client/djrandom_client/client.py index 60edf963f67981f0e8201ce1285da41ca1427a79..046b0eea8ee7ff27c67a9fe7760e2a57c5a82dac 100644 --- a/client/djrandom_client/client.py +++ b/client/djrandom_client/client.py @@ -11,6 +11,7 @@ from djrandom_client import daemonize from djrandom_client import filescan from djrandom_client import upload from djrandom_client import utils +from djrandom_client import throttle # Detect platform and selectively enable inotify/fsevents watchers. enable_watcher = True @@ -43,7 +44,10 @@ class FullScan(threading.Thread): time.sleep(86400 * 3) -def run_client(server_url, music_dir, api_key, run_once): +def run_client(server_url, music_dir, api_key, run_once, bwlimit): + if bwlimit: + throttle.set_rate_limit(bwlimit) + upl = upload.Uploader(server_url.rstrip('/'), api_key) scan = FullScan(music_dir, upl.queue, run_once) @@ -61,12 +65,18 @@ def run_client(server_url, music_dir, api_key, run_once): def main(): parser = optparse.OptionParser() - parser.add_option('--api_key') - parser.add_option('--once', action='store_true') + parser.add_option('--api_key', + help='Your API key') + parser.add_option('--once', action='store_true', + help='Scan music_dir once and then exit') parser.add_option('--music_dir', - default=os.path.join(os.getenv('HOME'), 'Music')) + default=os.path.join(os.getenv('HOME'), 'Music'), + help='Path to your music directory') parser.add_option('--server_url', - default='http://djrandom.incal.net/receiver') + default='http://djrandom.incal.net/receiver', + help='URL to the API endpoint') + parser.add_option('--bwlimit', type='int', + help='Bandwidth limit (in KBps, default unlimited)') daemonize.add_standard_options(parser) utils.read_config_defaults( parser, os.path.join(os.getenv('HOME'), '.djrandom.conf')) @@ -82,7 +92,7 @@ def main(): daemonize.daemonize(opts, run_client, (opts.server_url, opts.music_dir, opts.api_key, - opts.once)) + opts.once, opts.bwlimit)) if __name__ == '__main__': diff --git a/client/djrandom_client/throttle.py b/client/djrandom_client/throttle.py index 7fd095f9df782c48e7eb3ee18e6784b2fb442eaa..da63967fc24874a346b7981e809fd6e51d51277f 100644 --- a/client/djrandom_client/throttle.py +++ b/client/djrandom_client/throttle.py @@ -1,9 +1,12 @@ -import socket +import logging import httplib +import socket import threading import time import urllib2 +log = logging.getLogger(__name__) + class TokenBucket(object): """An implementation of the token bucket algorithm. @@ -55,10 +58,13 @@ _bucket = None def set_rate_limit(kbps): global _bucket - _bucket = TokenBucket(2 * kbps, kbps) + bps = 1024 * kbps + _bucket = TokenBucket(2 * bps, bps) + +class ThrottledHTTPConnection(httplib.HTTPConnection): -class ThrottledConnection(httplib.HTTPConnection): + BLOCK_SIZE = 4096 def send(self, str): if self.sock is None: @@ -71,14 +77,16 @@ class ThrottledConnection(httplib.HTTPConnection): print "send:", repr(str) try: tot = len(str) - for off in xrange(0, tot, BLOCK_SIZE): - n = min(BLOCK_SIZE, tot - off) + for off in xrange(0, tot, self.BLOCK_SIZE): + n = min(self.BLOCK_SIZE, tot - off) chunk = str[off:off + n] if _bucket: wait_time = _bucket.consume(n) while wait_time > 0: + log.debug('sleeping for %g secs' % wait_time) time.sleep(wait_time) wait_time = _bucket.consume(n) + log.debug('sending %d bytes' % n) self.sock.sendall(chunk) except socket.error, v: if v[0] == 32: # Broken pipe