From 1d984b810fe5618f3420bca0abc00d6625d6b480 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 5 Dec 2006 09:22:53 +0000 Subject: [PATCH] reduce size --- library/pytorrent.py | 85 +++++++++++++++++++++++++++++++------------- library/run_setup.py | 65 +++++++++++++++++++++++++++++++++ library/setup.py | 17 ++++----- library/test.py | 19 ++++++---- 4 files changed, 146 insertions(+), 40 deletions(-) create mode 100644 library/run_setup.py diff --git a/library/pytorrent.py b/library/pytorrent.py index 9dbe6e6ae..6a4d4e68d 100644 --- a/library/pytorrent.py +++ b/library/pytorrent.py @@ -1,6 +1,6 @@ # -# Copyright (C) 2006 Zach Tibbitts # Copyright (C) 2006 Alon Zakai ('Kripken') +# Copyright (C) 2006 Zach Tibbitts # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -17,11 +17,13 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # -# pytorrent-manager: backend/non-gui routines, that are not part of the core -# pytorrent module. pytorrent itself is mainly an interface to libtorrent, -# with some arrangements of exception classes for Python, etc.; also, some -# additional code that fits in well at the C++ level of libtorrent. All other -# backend routines should be in pytorrent-manager. +# Deluge Library, a.k.a. pytorrent: +# +# Deluge is a client. pytorrent is a Python library for torrenting, that includes +# pytorrent.py, which is Python code, and pytorrent_core, which is also a Python +# module, but written in C++, and includes the libtorrent torrent library. Only +# pytorrent should be visible, and only it should be imported, in the client. +# import pytorrent_core @@ -33,13 +35,16 @@ import time # Constants TORRENTS_SUBDIR = "torrentfiles" + STATE_FILENAME = "persistent.state" PREFS_FILENAME = "prefs.state" DHT_FILENAME = "dht.state" +TORRENT_STATE_EXPIRATION = 1 # seconds, like the output of time.time() + DEFAULT_PREFS = { # "max_half_open" : -1, -# "max_uploads" : -1 # Per torrent, read the libtorrent docs + "max_uploads" : 2, # a.k.a. upload slots "listen_on" : [6881,9999], "max_connections" : 80, "use_DHT" : True, @@ -49,6 +54,14 @@ DEFAULT_PREFS = { "max_upload_rate" : -1 } +# Exception + +class PyTorrentError(Exception): + def __init__(self, value): + self.value = value + def __str__(self): + return repr(self.value) + # Information for a single torrent @@ -99,6 +112,10 @@ class manager: # Unique IDs are NOT in the state, since they are temporary for each session self.unique_IDs = {} # unique_ID -> a torrent object + # Saved torrent states. We do not poll the core in a costly manner, necessarily + self.saved_torrent_states = {} # unique_ID -> torrent_state + self.saved_torrent_states_timestamp = {} # time of creation + # Unpickle the preferences, or create a new one try: pkl_file = open(self.base_dir + "/" + PREFS_FILENAME, 'rb') @@ -107,9 +124,10 @@ class manager: except IOError: self.prefs = DEFAULT_PREFS + # Apply preferences. Note that this is before any torrents are added self.apply_prefs() - # Apply DHT, if needed + # Apply DHT, if needed. Note that this is before any torrents are added if self.get_pref('use_DHT'): pytorrent_core.start_DHT(self.base_dir + "/" + DHT_FILENAME) @@ -155,7 +173,14 @@ class manager: self.prefs[key] = DEFAULT_PREFS[key] return self.prefs[key] else: - raise PyTorrentCoreError("Asked for a pref that doesn't exist: " + key) + raise PyTorrentError("Asked for a pref that doesn't exist: " + key) + + def set_pref(self, key, value): + # Make sure this is a valid key + if key not in DEFAULT_PREFS.keys(): + raise PyTorrentError("Asked to change a pref that isn't valid: " + key) + + self.prefs[key] = value def apply_prefs(self): pytorrent_core.set_download_rate_limit(self.get_pref('max_download_rate')*1024) @@ -165,10 +190,11 @@ class manager: pytorrent_core.set_listen_on(self.get_pref('listen_on')[0], self.get_pref('listen_on')[1]) - pytorrent_core.set_max_connections(self.get_pref('max_connections')*1024) + pytorrent_core.set_max_connections(self.get_pref('max_connections')) + + pytorrent_core.set_max_uploads(self.get_pref('max_uploads')) def add_torrent(self, filename, save_dir, compact): - print "add_torrent" self.add_torrent_ns(filename, save_dir, compact) return self.sync() # Syncing will create a new torrent in the core, and return it's ID @@ -204,8 +230,20 @@ class manager: for unique_ID in self.unique_IDs: pytorrent_core.save_fastresume(unique_ID, self.unique_IDs[unique_ID].filename) - def get_state(self, unique_ID): - return pytorrent_core.get_state(unique_ID) + # Efficient get_state: use a saved state, if it hasn't expired yet + def get_state(self, unique_ID, efficiently = False): + if efficiently: + try: + if time.time() < self.saved_torrent_states_timestamp[unique_ID] + \ + TORRENT_STATE_EXPIRATION: + return self.saved_torrent_states[unique_ID] + except KeyError: + pass + + self.saved_torrent_states_timestamp[unique_ID] = time.time() + self.saved_torrent_states[unique_ID] = pytorrent_core.get_state(unique_ID) + + return self.saved_torrent_states[unique_ID] def queue_up(self, unique_ID): curr_index = self.get_queue_index(unique_ID) @@ -229,7 +267,7 @@ class manager: def clear_completed(self): for unique_ID in self.unique_IDs: - torrent_state = pytorrent_core.get_state(unique_ID) + torrent_state = self.get_state(unique_ID, True) if torrent_state['progress'] == 100.0: self.remove_torrent_ns(unique_ID) @@ -242,9 +280,6 @@ class manager: def is_user_paused(self, unique_ID): return self.unique_IDs[unique_ID].user_paused - def is_paused(self, unique_ID): - return pytorrent_core.is_paused(unique_ID) - # Enforce the queue: pause/unpause as needed, based on queue and user_pausing # This should be called after changes to relevant parameters (user_pausing, or # altering max_active_torrents), or just from time to time @@ -255,7 +290,7 @@ class manager: if self.auto_seed_ratio != -1: for unique_ID in self.unique_IDs: if pytorrent_core.is_seeding(unique_ID): - torrent_state = pytorrent_core.get_state(unique_ID) + torrent_state = self.get_state(unique_ID, True) ratio = self.calc_ratio(unique_ID, torrent_state) if ratio >= self.auto_seed_ratio: self.queue_bottom(unique_ID) @@ -264,10 +299,10 @@ class manager: for index in range(len(self.state.queue)): unique_ID = self.state.queue[index] if (index < self.state.max_active_torrents or self.state_max_active_torrents == -1) \ - and self.is_paused(unique_ID) \ + and pytorrent_core.is_paused(unique_ID) \ and not self.is_user_paused(unique_ID): pytorrent_core.resume(unique_ID) - elif not self.is_paused(unique_ID) and \ + elif not pytorrent_core.is_paused(unique_ID) and \ (index >= self.state.max_active_torrents or self.is_user_paused(unique_ID)): pytorrent_core.pause(unique_ID) @@ -282,6 +317,8 @@ class manager: return ret + def get_num_torrents(self): + return pytorrent_core.get_num_torrents() #################### # Internal functions @@ -298,7 +335,7 @@ class manager: full_new_name = self.base_dir + "/" + TORRENTS_SUBDIR + "/" + new_name if new_name in os.listdir(self.base_dir + "/" + TORRENTS_SUBDIR): - raise PyTorrentCoreError("Could not cache torrent file locally, failed: " + new_name) + raise PyTorrentError("Could not cache torrent file locally, failed: " + new_name) shutil.copy(filename, full_new_name) @@ -314,8 +351,6 @@ class manager: # Also all self-syncing is done here (various lists) def sync(self): - print "sync" - ret = None # We return new added unique ID(s), or None # Add torrents to core and unique_IDs @@ -323,11 +358,11 @@ class manager: for torrent in self.state.torrents: if torrent not in torrents_with_unique_ID: - print "Adding torrent to core:", torrent.filename, torrent.save_dir, torrent.compact +# print "Adding torrent to core:", torrent.filename, torrent.save_dir, torrent.compact unique_ID = pytorrent_core.add_torrent(torrent.filename, torrent.save_dir, torrent.compact) - print "Got unique ID:", unique_ID +# print "Got unique ID:", unique_ID ret = unique_ID self.unique_IDs[unique_ID] = torrent diff --git a/library/run_setup.py b/library/run_setup.py new file mode 100644 index 000000000..03937afe5 --- /dev/null +++ b/library/run_setup.py @@ -0,0 +1,65 @@ +# +# Copyright (c) 2006 Alon Zakai ('Kripken') +# +# 2006-15-9 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +import sys +command = sys.argv[1] + +assert(command in ['build', 'install']) + +removals = ['-g', '-DNDEBUG', '-O2', '-Wstrict-prototypes'] +addition = "-DNDEBUG -Os" + +import platform + +pythonVersion = platform.python_version()[0:3] + +print "=========================================" +print "Creating pytorrent_core for Python " + pythonVersion +print "=========================================" + +import os + +p = os.popen("python setup.py --dry-run build") +data = p.readlines() +p.close() + +print "Executing modified commands: " +for line in data: + if line[0:3] in ['gcc', 'g++']: +# print "OLD: ", line + for removal in removals: + line = line.replace(" " + removal + " ", " ") + line = line[0:4] + addition + " " + line[4:] + print line + + p = os.popen(line) + data = p.readlines() + p.close() + + print "" + +# Now redo it, for real. Nothing should occur, except for installation, if requested +print "Finalizing..." + +p = os.popen("python setup.py " + command) +data = p.readlines() +p.close() + +print "".join(data) diff --git a/library/setup.py b/library/setup.py index 79546135b..8d0611c19 100644 --- a/library/setup.py +++ b/library/setup.py @@ -22,10 +22,6 @@ import platform pythonVersion = platform.python_version()[0:3] -print "=========================================" -print "Creating pytorrent_core for Python " + pythonVersion -print "=========================================" - from distutils.core import setup, Extension module1 = Extension('pytorrent_core', @@ -34,6 +30,8 @@ module1 = Extension('pytorrent_core', libraries = ['boost_filesystem', 'boost_date_time', 'boost_program_options', 'boost_regex', 'boost_serialization', 'boost_thread', 'z', 'pthread'], + extra_compile_args = ["-Wno-missing-braces"], +# extra_link_args = [""], sources = ['alert.cpp', 'allocate_resources.cpp', 'bt_peer_connection.cpp', @@ -68,7 +66,10 @@ module1 = Extension('pytorrent_core', './kademlia/rpc_manager.cpp', './kademlia/traversal_algorithm.cpp']) -setup (name = 'pytorrent_core', - version = '0.5.0', - description = 'Wrapper code for libtorrent C++ torrent library (Sourceforge, not Rakshasa)', - ext_modules = [module1]) +setup(name = 'pytorrent_core', + version = '0.5.0', + description = 'A module for the bittorrent protocol. Built using (Sourgeforge, not Rakshasha) libtorrent.', + author="Alon Zakai ('Kripken'), Zach Tibbitts", + author_email="kripkensteiner@gmail.com", + url="http://www.deluge-torrent.org", + ext_modules = [module1]) diff --git a/library/test.py b/library/test.py index 3248e07c6..fd3124869 100644 --- a/library/test.py +++ b/library/test.py @@ -16,15 +16,20 @@ import os manager = pytorrent.manager("PT", "0500", "pytorrent - testing only", os.path.expanduser("~") + "/Temp") +#manager.prefs['max_active_torrents'] = 1 + #my_torrent = manager.add_torrent("ubuntu.torrent", ".", True) #print "Unique ID:", my_torrent -for i in range(2): - print "STATE:" - print manager.get_state(0)#my_torrent) - print "" +print "PREFS:", manager.prefs - sleep(2) - -manager.quit() +try: + while True: + print "STATE:", manager.get_num_torrents() + for j in range(manager.get_num_torrents()): + print manager.get_state(j) + print "" + sleep(2) +except KeyboardInterrupt: + manager.quit()