class LaunchMany(object): def __init__(self, config, display, configfile_key): """Starts torrents for all .torrent files in a directory tree. All errors are logged using Python logging to 'configfile_key' logger. @param config: Preferences object storing config. @param display: output function for stats. """ # 4.4.x version of LaunchMany output exceptions to a displayer. # This version only outputs stats to the displayer. We do not use # the logger to output stats so that a caller-provided object # can provide stats formatting as opposed to using the # logger Formatter, which is specific to exceptions, warnings, and # info messages. self.logger = logging.getLogger(configfile_key) try: self.multitorrent = None self.rawserver = None self.config = config self.configfile_key = configfile_key self.display = display self.torrent_dir = config['torrent_dir'] # Ex: torrent_cache = infohash -> (path,metainfo) self.torrent_cache = {} # maps path -> [(modification time, size), infohash] self.file_cache = {} # used as set containing paths of files that do not have separate # entries in torrent_cache either because torrent_cache already # contains the torrent or because the torrent file is corrupt. self.blocked_files = {} #self.torrent_list = [] #self.downloads = {} self.hashcheck_queue = [] #self.hashcheck_store = {} self.hashcheck_current = None self.core_doneflag = DeferredEvent() self.rawserver = RawServer(self.config) try: # set up shut-down procedure before we begin doing things that # can throw exceptions. def shutdown(): self.logger.critical(_("shutting down")) for t in self.multitorrent.get_torrents(): self.logger.info(_('dropped "%s"') % self.torrent_cache[t.infohash][0]) if self.multitorrent: df = self.multitorrent.shutdown() set_flag = lambda *a : self.rawserver.stop() df.addCallbacks(set_flag, set_flag) else: self.rawserver.stop() # It is safe to addCallback here, because there is only one thread, # but even if the code were multi-threaded, core_doneflag has not # been passed to anyone. There is no chance of a race condition # between the DeferredEvent's callback and addCallback. self.core_doneflag.addCallback( lambda r: self.rawserver.external_add_task(0, shutdown)) self.rawserver.install_sigint_handler(self.core_doneflag) data_dir = config['data_dir'] self.multitorrent = MultiTorrent(config, self.rawserver, data_dir, resume_from_torrent_config=False) self.rawserver.add_task(0, self.scan) self.rawserver.add_task(0.5, self.periodic_check_hashcheck_queue) self.rawserver.add_task(self.config['display_interval'], self.periodic_stats) try: import signal def handler(signum, frame): self.rawserver.external_add_task(0, self.read_config) signal.signal(signal.SIGHUP, handler) except Exception, e: self.logger.error(_("Could not set signal handler: ") + unicode(e.args[0])) self.rawserver.add_task(0,self.core_doneflag.set()) except UserFailure, e: self.logger.error(unicode(e.args[0])) self.rawserver.add_task(0,self.core_doneflag.set()) except: data = StringIO() print_exc(file = data) self.logger.error(data.getvalue()) self.rawserver.add_task(0,self.core_doneflag.set()) # always make sure events get processed even if only for # shutting down. self.rawserver.listen_forever() except: