diff options
author | Jeffrey C. Ollie <jeff@ocjtech.us> | 2008-08-19 19:34:21 -0500 |
---|---|---|
committer | Jeffrey C. Ollie <jeff@ocjtech.us> | 2008-08-19 19:34:21 -0500 |
commit | cfc058e6ecd9d7e132d5ccf4600ead1f0641ddc9 (patch) | |
tree | 5d9d4756703d8e640a60188abd818b74d5e0cca9 /NohGooee/launchmanycore.py | |
parent | ad0fe53806ab5da2ead4a790af22f47e4ea2e713 (diff) | |
download | nohgooee-cfc058e6ecd9d7e132d5ccf4600ead1f0641ddc9.tar.gz nohgooee-cfc058e6ecd9d7e132d5ccf4600ead1f0641ddc9.tar.xz nohgooee-cfc058e6ecd9d7e132d5ccf4600ead1f0641ddc9.zip |
Some renames.
Diffstat (limited to 'NohGooee/launchmanycore.py')
-rw-r--r-- | NohGooee/launchmanycore.py | 261 |
1 files changed, 261 insertions, 0 deletions
diff --git a/NohGooee/launchmanycore.py b/NohGooee/launchmanycore.py new file mode 100644 index 0000000..bf83fea --- /dev/null +++ b/NohGooee/launchmanycore.py @@ -0,0 +1,261 @@ +# The contents of this file are subject to the BitTorrent Open Source License +# Version 1.1 (the License). You may not copy or use this file, in either +# source code or executable form, except in compliance with the License. You +# may obtain a copy of the License at http://www.bittorrent.com/license/. +# +# Software distributed under the License is distributed on an AS IS basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. + +# Original version written by John Hoffman, heavily modified for different +# multitorrent architecture by Uoti Urpala (over 40% shorter than original) + +import os +from cStringIO import StringIO +from traceback import print_exc + +from NohGooee import configfile +from NohGooee.parsedir import parsedir +from NohGooee.download import Multitorrent, Feedback +from NohGooee.ConvertedMetainfo import ConvertedMetainfo +from NohGooee import BTFailure + +from threading import Event +from time import time + + +class LaunchMany(Feedback): + + def __init__(self, config, output, configfile_key): + try: + self.config = config + self.output = output + self.configfile_key = configfile_key + + self.torrent_dir = config['torrent_dir'] + self.torrent_cache = {} + self.file_cache = {} + self.blocked_files = {} + + self.torrent_list = [] + self.downloads = {} + self.doneflag = Event() + + self.hashcheck_queue = [] + self.hashcheck_store = {} + self.hashcheck_current = None + + self.multitorrent = Multitorrent(config, self.doneflag, + self.global_error) + self.rawserver = self.multitorrent.rawserver + + self.rawserver.add_task(self.scan, 0) + self.rawserver.add_task(self.stats, 0) + + try: + import signal + def handler(signum, frame): + self.rawserver.external_add_task(self.read_config, 0) + signal.signal(signal.SIGHUP, handler) + self.rawserver.install_sigint_handler() + except Exception, e: + self.output.message(_("Could not set signal handler: ") + str(e)) + + self.rawserver.listen_forever() + + self.output.message(_("shutting down")) + for infohash in self.torrent_list: + self.output.message(_('dropped "%s"') % + self.torrent_cache[infohash]['path']) + torrent = self.downloads[infohash] + if torrent is not None: + torrent.shutdown() + except: + data = StringIO() + print_exc(file = data) + output.exception(data.getvalue()) + + def scan(self): + self.rawserver.add_task(self.scan, self.config['parse_dir_interval']) + + r = parsedir(self.torrent_dir, self.torrent_cache, + self.file_cache, self.blocked_files, + self.output.message) + + ( self.torrent_cache, self.file_cache, self.blocked_files, + added, removed ) = r + + for infohash, data in removed.items(): + self.output.message(_('dropped "%s"') % data['path']) + self.remove(infohash) + for infohash, data in added.items(): + self.output.message(_('added "%s"' ) % data['path']) + if self.config['launch_delay'] > 0: + self.rawserver.add_task(self.add, self.config['launch_delay'], (infohash, data)) + else: + self.add(infohash, data) + + def stats(self): + self.rawserver.add_task(self.stats, self.config['display_interval']) + data = [] + for infohash in self.torrent_list: + cache = self.torrent_cache[infohash] + if self.config['display_path']: + name = cache['path'] + else: + name = cache['name'] + size = cache['length'] + d = self.downloads[infohash] + progress = '0.0%' + peers = 0 + seeds = 0 + seedsmsg = "S" + dist = 0.0 + uprate = 0.0 + dnrate = 0.0 + upamt = 0 + dnamt = 0 + t = 0 + msg = '' + if d is None: + status = _("waiting for hash check") + else: + stats = d.get_status() + status = stats['activity'] + progress = '%.1f%%' % (int(stats['fractionDone']*1000)/10.0) + if d.started and not d.closed: + s = stats + dist = s['numCopies'] + if d.is_seed: + seeds = 0 # s['numOldSeeds'] + seedsmsg = "s" + else: + if s['numSeeds'] + s['numPeers']: + t = stats['timeEst'] + if t is None: + t = -1 + if t == 0: # unlikely + t = 0.01 + status = _("downloading") + else: + t = -1 + status = _("connecting to peers") + seeds = s['numSeeds'] + dnrate = stats['downRate'] + peers = s['numPeers'] + uprate = stats['upRate'] + upamt = s['upTotal'] + dnamt = s['downTotal'] + if d.errors and (d.closed or d.errors[-1][0] + 300 > time()): + msg = d.errors[-1][2] + + data.append(( name, status, progress, peers, seeds, seedsmsg, dist, + uprate, dnrate, upamt, dnamt, size, t, msg )) + stop = self.output.display(data) + if stop: + self.doneflag.set() + + def remove(self, infohash): + self.torrent_list.remove(infohash) + if self.downloads[infohash] is not None: + self.downloads[infohash].shutdown() + self.was_stopped(infohash) + del self.downloads[infohash] + + def add(self, infohash, data): + self.torrent_list.append(infohash) + self.downloads[infohash] = None + self.hashcheck_queue.append(infohash) + self.hashcheck_store[infohash] = data['metainfo'] + self.check_hashcheck_queue() + + def check_hashcheck_queue(self): + if self.hashcheck_current is not None or not self.hashcheck_queue: + return + self.hashcheck_current = self.hashcheck_queue.pop(0) + metainfo = self.hashcheck_store[self.hashcheck_current] + del self.hashcheck_store[self.hashcheck_current] + filename = self.determine_filename(self.hashcheck_current) + self.downloads[self.hashcheck_current] = self.multitorrent. \ + start_torrent(ConvertedMetainfo(metainfo), + self.config, self, filename) + + def determine_filename(self, infohash): + x = self.torrent_cache[infohash] + name = x['name'] + savein = self.config['save_in'] + isdir = not x['metainfo']['info'].has_key('length') + style = self.config['saveas_style'] + if style == 4: + torrentname = os.path.split(x['path'][:-8])[1] + suggestedname = name + if torrentname == suggestedname: + style = 1 + else: + style = 3 + + if style == 1 or style == 3: + if savein: + saveas = os.path.join(savein,x['file'][:-8]) # strip '.torrent' + else: + saveas = x['path'][:-8] # strip '.torrent' + if style == 3 and not isdir: + saveas = os.path.join(saveas, name) + else: + if savein: + saveas = os.path.join(savein, name) + else: + saveas = os.path.join(os.path.split(x['path'])[0], name) + return saveas + + def was_stopped(self, infohash): + try: + self.hashcheck_queue.remove(infohash) + except: + pass + else: + del self.hashcheck_store[infohash] + if self.hashcheck_current == infohash: + self.hashcheck_current = None + self.check_hashcheck_queue() + + def global_error(self, level, text): + self.output.message(text) + + def exchandler(self, s): + self.output.exception(s) + + def read_config(self): + try: + newvalues = configfile.get_config(self.config, self.configfile_key) + except Exception, e: + self.output.message(_("Error reading config: ") + str(e)) + return + self.output.message(_("Rereading config file")) + self.config.update(newvalues) + # The set_option call can potentially trigger something that kills + # the torrent (when writing this the only possibility is a change in + # max_files_open causing an IOError while closing files), and so + # the self.failed() callback can run during this loop. + for option, value in newvalues.iteritems(): + self.multitorrent.set_option(option, value) + for torrent in self.downloads.values(): + if torrent is not None: + for option, value in newvalues.iteritems(): + torrent.set_option(option, value) + + # rest are callbacks from torrent instances + + def started(self, torrent): + self.hashcheck_current = None + self.check_hashcheck_queue() + + def failed(self, torrent, is_external): + infohash = torrent.infohash + self.was_stopped(infohash) + if self.torrent_cache.has_key(infohash): + self.output.message('DIED: "'+self.torrent_cache[infohash]['path']+'"') + + def exception(self, torrent, text): + self.exchandler(text) |