📄 multitorrent.py
字号:
for policy in self.policies: policy.error(torrent, level, text) ### persistence ## These should be the .torrent file! ################# def _dump_metainfo(self, metainfo): infohash = metainfo.infohash path = os.path.join(self.data_dir, 'metainfo', infohash.encode('hex')) f = file(path+'.new', 'wb') f.write(metainfo.to_data()) f.close() shutil.move(path+'.new', path) def _read_metainfo(self, infohash): path = os.path.join(self.data_dir, 'metainfo', infohash.encode('hex')) f = file(path, 'rb') data = f.read() f.close() return ConvertedMetainfo(bdecode(data)) ################# def _read_torrent_config(self, infohash): path = os.path.join(self.data_dir, 'torrents', infohash.encode('hex')) if not os.path.exists(path): raise BTFailure,_("Coult not open the torrent config: " + infohash.encode('hex')) f = file(path, 'rb') data = f.read() f.close() try: torrent_config = cPickle.loads(data) except: # backward compatibility with <= 4.9.3 torrent_config = bdecode(data) for k, v in torrent_config.iteritems(): try: torrent_config[k] = v.decode('utf8') if k in ('destination_path', 'working_path'): torrent_config[k] = encode_for_filesystem(torrent_config[k])[0] except: pass if not torrent_config.get('destination_path'): raise BTFailure( _("Invalid torrent config file")) if not torrent_config.get('working_path'): raise BTFailure( _("Invalid torrent config file")) if get_filesystem_encoding() == None: # These paths should both be unicode. If they aren't, they are the # broken product of some old version, and probably are in the # encoding we used to use in config files. Attempt to recover. dp = torrent_config['destination_path'] if isinstance(dp, str): try: dp = dp.decode(old_broken_config_subencoding) torrent_config['destination_path'] = dp except: raise BTFailure( _("Invalid torrent config file")) wp = torrent_config['working_path'] if isinstance(wp, str): try: wp = wp.decode(old_broken_config_subencoding) torrent_config['working_path'] = wp except: raise BTFailure( _("Invalid torrent config file")) return torrent_config def _dump_global_config(self): # BUG: we can save to different sections later section = 'bittorrent' configfile.save_global_config(self.config, section, lambda *e : self.logger.error(*e)) def _dump_torrents(self): assert self.resume_from_torrent_config self.last_save_time = bttime() r = [] def write_entry(infohash, t): r.append(' '.join((infohash.encode('hex'), str(t.uptotal), str(t.downtotal)))) r.append('BitTorrent UI state file, version 5') r.append('Queued torrents') for t in self.torrents.values(): write_entry(t.metainfo.infohash, self.torrents[t.metainfo.infohash]) r.append('End') f = None try: path = os.path.join(self.data_dir, 'ui_state') f = file(path+'.new', 'wb') f.write('\n'.join(r) + '\n') f.close() shutil.move(path+'.new', path) except Exception, e: self.logger.error(_("Could not save UI state: ") + unicode(e.args[0])) if f is not None: f.close() def _init_torrent(self, t, initialize=True, use_policy=True): self.torrents[t.infohash] = t if not initialize: t.logger.debug("created torrent") return t.logger.debug("created torrent, initializing") df = t.initialize() if use_policy and t.policy == "start": df.addCallback(lambda r, t: self.start_torrent(t.infohash), t) return df def initialize_torrents(self): df = launch_coroutine(_wrap_task(self.rawserver.add_task), self._initialize_torrents) df.addErrback(lambda e : self.logger.error('initialize_torrents failed!', exc_info=e)) return df def _initialize_torrents(self): self.logger.debug("initializing torrents") for t in copy(self.torrents).itervalues(): if t in self.torrents.values() and t.state == "created": df = self._init_torrent(t) # HACK #yield df #df.getResult() # this function is so nasty! def _restore_state(self, init_torrents): def decode_line(line): hashtext = line[:40] try: infohash = InfoHashType(hashtext.decode('hex')) except: raise BTFailure(_("Invalid state file contents")) if len(infohash) != 20: raise BTFailure(_("Invalid state file contents")) if infohash in self.torrents: raise BTFailure(_("Invalid state file (duplicate entry)")) try: metainfo = self._read_metainfo(infohash) except OSError, e: try: f.close() except: pass self.logger.error((_("Error reading metainfo file \"%s\".") % hashtext) + " (" + unicode(e.args[0])+ "), " + _("cannot restore state completely")) return None except Exception, e: self.logger.error((_("Corrupt data in metainfo \"%s\", cannot restore torrent.") % hashtext) + '('+unicode(e.args[0])+')') return None t = Torrent(metainfo, "", "", self.config, self.data_dir, self.rawserver, self.choker, self.singleport_listener, self.ratelimiter, self.total_downmeasure, self.filepool, self.dht, self, self.log_root) t.metainfo.reported_errors = True # suppress redisplay on restart if infohash != t.metainfo.infohash: self.logger.error((_("Corrupt data in \"%s\", cannot restore torrent.") % hashtext) + _("(infohash mismatch)")) return None if len(line) == 41: t.working_path = None t.destination_path = None return infohash, t try: if version < 2: t.working_path = line[41:-1].decode('string_escape') t.working_path = t.working_path.decode('utf-8') t.working_path = encode_for_filesystem(t.working_path)[0] t.destination_path = t.working_path elif version == 3: up, down, working_path = line[41:-1].split(' ', 2) t.uptotal = t.uptotal_old = int(up) t.downtotal = t.downtotal_old = int(down) t.working_path = working_path.decode('string_escape') t.working_path = t.working_path.decode('utf-8') t.working_path = encode_for_filesystem(t.working_path)[0] t.destination_path = t.working_path elif version >= 4: up, down = line[41:-1].split(' ', 1) t.uptotal = t.uptotal_old = int(up) t.downtotal = t.downtotal_old = int(down) except ValueError: # unpack, int(), decode() raise BTFailure(_("Invalid state file (bad entry)")) torrent_config = self.config try: if version < 5: torrent_config = configfile.read_torrent_config( self.config, self.data_dir, infohash, lambda s : self.global_error(logging.ERROR, s)) else: torrent_config = self._read_torrent_config(infohash) t.update_config(torrent_config) except BTFailure, e: self.logger.error("Read torrent config failed", exc_info=sys.exc_info()) # if read_torrent_config fails then ignore the torrent... return None return infohash, t # BEGIN _restore_state assert self.resume_from_torrent_config filename = os.path.join(self.data_dir, 'ui_state') if not os.path.exists(filename): return f = None try: f = file(filename, 'rb') lines = f.readlines() f.close() except Exception, e: if f is not None: f.close() raise BTFailure(unicode(e.args[0])) i = iter(lines) try: txt = 'BitTorrent UI state file, version ' version = i.next() if not version.startswith(txt): raise BTFailure(_("Bad UI state file")) try: version = int(version[len(txt):-1]) except: raise BTFailure(_("Bad UI state file version")) if version > 5: raise BTFailure(_("Unsupported UI state file version (from " "newer client version?)")) if version < 3: if i.next() != 'Running/queued torrents\n': raise BTFailure(_("Invalid state file contents")) else: if i.next() != 'Running torrents\n' and version != 5: raise BTFailure(_("Invalid state file contents")) while version < 5: line = i.next() if line == 'Queued torrents\n': break t = decode_line(line) if t is None: continue infohash, t = t df = self._init_torrent(t, initialize=init_torrents) while True: line = i.next() if (version < 5 and line == 'Known torrents\n') or (version == 5 and line == 'End\n'): break t = decode_line(line) if t is None: continue infohash, t = t if t.destination_path is None: raise BTFailure(_("Invalid state file contents")) df = self._init_torrent(t, initialize=init_torrents) while version < 5: line = i.next() if line == 'End\n': break t = decode_line(line) if t is None: continue infohash, t = t df = self._init_torrent(t, initialize=init_torrents) except StopIteration: raise BTFailure(_("Invalid state file contents"))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -