⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 torrentqueue.py

📁 BitTorrent(简称BT
💻 PY
📖 第 1 页 / 共 2 页
字号:
# The contents of this file are subject to the BitTorrent Open Source License# Version 1.0 (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.# Written by Uoti Urpalafrom __future__ import divisionimport osimport sysimport threadingfrom BitTorrent.platform import bttimefrom BitTorrent.download import Feedback, Multitorrentfrom BitTorrent.controlsocket import ControlSocketfrom BitTorrent.bencode import bdecodefrom BitTorrent.ConvertedMetainfo import ConvertedMetainfofrom BitTorrent import BTFailure, BTShutdown, INFO, WARNING, ERROR, CRITICALfrom BitTorrent import configfilefrom BitTorrent import FAQ_URLimport BitTorrent# check if dns library from http://www.dnspython.org/ is either installed# or the dns subdirectory has been copied to BitTorrent/dnsHAVE_DNS = Falsetry:    from BitTorrent import dns    sys.modules['dns'] = dns    import dns.resolver    HAVE_DNS = Trueexcept:    try:        import dns.resolver        HAVE_DNS = True    except:        passRUNNING = 0RUN_QUEUED = 1QUEUED = 2KNOWN = 3ASKING_LOCATION = 4class TorrentInfo(object):    def __init__(self):        self.metainfo = None        self.dlpath = None        self.dl = None        self.state = None        self.completion = None        self.finishtime = None        self.uptotal = 0        self.uptotal_old = 0        self.downtotal = 0        self.downtotal_old = 0def decode_position(l, pred, succ, default=None):    if default is None:        default = len(l)    if pred is None and succ is None:        return default    if pred is None:        return 0    if succ is None:        return len(l)    try:        if l[0] == succ and pred not in l:            return 0        if l[-1] == pred and succ not in l:            return len(l)        i = l.index(pred)        if l[i+1] == succ:            return i+1    except (ValueError, IndexError):        pass    return defaultclass TorrentQueue(Feedback):    def __init__(self, config, ui_options, controlsocket):        self.config = dict(config)        self.ui_options = ui_options        self.controlsocket = controlsocket        self.config['def_running_torrents'] = 1 # !@# XXX        self.config['max_running_torrents'] = 3 # !@# XXX        self.doneflag = threading.Event()        self.torrents = {}        self.starting_torrent = None        self.running_torrents = []        self.queue = []        self.other_torrents = []        self.last_save_time = 0        self.last_version_check = 0    def run(self, ui, ui_wrap, startflag):        self.ui = ui        self.run_ui_task = ui_wrap        self.multitorrent = Multitorrent(self.config, self.doneflag,                                        self.global_error, listen_fail_ok=True)        self.rawserver = self.multitorrent.rawserver        self.controlsocket.set_rawserver(self.rawserver)        self.controlsocket.start_listening(self.external_command)        try:            self._restore_state()        except BTFailure, e:            self.queue = []            self.other_torrents = []            self.torrents = {}            self.global_error(ERROR, "Could not load saved state: "+str(e))        else:            for infohash in self.running_torrents + self.queue + \                    self.other_torrents:                t = self.torrents[infohash]                if t.dlpath is not None:                    t.completion = self.multitorrent.get_completion(                        self.config, t.metainfo, t.dlpath)                state = t.state                if state == RUN_QUEUED:                    state = RUNNING                self.run_ui_task(self.ui.new_displayed_torrent, infohash,                                 t.metainfo, t.dlpath, state, t.completion,                                 t.uptotal, t.downtotal)        self._check_queue()        startflag.set()        self._queue_loop()        self._check_version()        self.multitorrent.rawserver.listen_forever()        self.multitorrent.close_listening_socket()        self.controlsocket.close_socket()        for infohash in list(self.running_torrents):            t = self.torrents[infohash]            if t.state == RUN_QUEUED:                continue            t.dl.shutdown()            if t.dl is not None:  # possibly set to none by failed()                totals = t.dl.get_total_transfer()                t.uptotal = t.uptotal_old + totals[0]                t.downtotal = t.downtotal_old + totals[1]        self._dump_state()    def _check_version(self):        now = bttime()        if self.last_version_check > now - 24*3600:            return        self.last_version_check = now        if not HAVE_DNS:            self.global_error(WARNING, "Version check failed: no DNS library")            return        threading.Thread(target=self._version_thread).start()    def _version_thread(self):        def error(level, text):            def f():                self.global_error(level, text)            self.rawserver.external_add_task(f, 0)        def splitversion(text):            return [int(t) for t in text.split('.')]        try:            try:                a = dns.resolver.query('version.bittorrent.com', 'TXT')            except:                # the exceptions from the library have empty str(),                # just different classes...                raise BTFailure('DNS query failed')            if len(a) != 1:                raise BTFailure('number of received TXT fields is not 1')            value = iter(a).next() # the object doesn't support a[0]            if len(value.strings) != 1:                raise BTFailure('number of strings in reply is not 1?')            s = value.strings[0].split(None, 2)            myversion = splitversion(BitTorrent.version)            if myversion[1] % 2 and len(s) > 1:                s = s[1]            else:                s = s[0]            try:                latest = splitversion(s)            except ValueError:                raise BTFailure("Could not parse new version string")            for my, new in zip(myversion, latest):                if my > new:                    break                if my < new:                    download_url = 'http://bittorrent.com/download.html'                    if hasattr(self.ui, 'new_version'):                        self.run_ui_task(self.ui.new_version, s,                                         download_url)                    else:                        error(ERROR, "A newer version of BitTorrent is "                              "available.\nYou can always get the latest "                              "version from\n%s." % download_url)        except Exception, e:            error(WARNING, "Version check failed: " + str(e))    def _dump_config(self):        configfile.save_ui_config(self.config, 'btdownloadgui',                               self.ui_options, self.global_error)    def _dump_state(self):        self.last_save_time = bttime()        r = []        def write_entry(infohash, t):            if t.dlpath is None:                assert t.state == ASKING_LOCATION                r.append(infohash.encode('hex') + '\n')            else:                r.append(infohash.encode('hex') + ' ' + str(t.uptotal) + ' ' +                    str(t.downtotal)+' '+t.dlpath.encode('string_escape')+'\n')        r.append('BitTorrent UI state file, version 3\n')        r.append('Running torrents\n')        for infohash in self.running_torrents:            write_entry(infohash, self.torrents[infohash])        r.append('Queued torrents\n')        for infohash in self.queue:            write_entry(infohash, self.torrents[infohash])        r.append('Known torrents\n')        for infohash in self.other_torrents:            write_entry(infohash, self.torrents[infohash])        r.append('End\n')        f = None        try:            f = file(os.path.join(self.config['data_dir'], 'ui_state'), 'wb')            f.write(''.join(r))            f.close()        except Exception, e:            self.global_error(ERROR, 'Could not save UI state: ' + str(e))            if f is not None:                f.close()    def _restore_state(self):        def decode_line(line):            hashtext = line[:40]            try:                infohash = hashtext.decode('hex')            except:                raise BTFailure("Invalid state file contents")            if len(infohash) != 20:                raise BTFailure("Invalid state file contents")            try:                path = os.path.join(self.config['data_dir'], 'metainfo',                                    hashtext)                f = file(path, 'rb')                data = f.read()                f.close()            except Exception, e:                try:                    f.close()                except:                    pass                self.global_error(ERROR,"Error reading file "+path+" ("+str(e)+                                  "), cannot restore state completely")                return None            if infohash in self.torrents:                raise BTFailure("Invalid state file (duplicate entry)")            t = TorrentInfo()            self.torrents[infohash] = t            try:                t.metainfo = ConvertedMetainfo(bdecode(data))            except Exception, e:                self.global_error(ERROR, "Corrupt data in "+path+                                  " , cannot restore torrent ("+str(e)+")")                return None            t.metainfo.reported_errors = True # suppress redisplay on restart            if infohash != t.metainfo.infohash:                self.global_error(ERROR, "Corrupt data in "+path+                                  " , cannot restore torrent ("+str(e)+")")                return None            if len(line) == 41:                t.dlpath = None                return infohash, t            try:                if version < 2:                    t.dlpath = line[41:-1].decode('string_escape')                else:                    up, down, dlpath = line[41:-1].split(' ', 2)                    t.uptotal = t.uptotal_old = int(up)                    t.downtotal = t.downtotal_old = int(down)                    t.dlpath = dlpath.decode('string_escape')            except ValueError:  # unpack, int(), decode()                raise BTFailure('Invalid state file (bad entry)')            return infohash, t        filename = os.path.join(self.config['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(str(e))        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 > 3:                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":                    raise BTFailure("Invalid state file contents")                while True:                    line = i.next()                    if line == 'Queued torrents\n':                        break                    t = decode_line(line)                    if t is None:                        continue                    infohash, t = t                    if t.dlpath is None:                        raise BTFailure("Invalid state file contents")                    t.state = RUN_QUEUED                    self.running_torrents.append(infohash)            while True:                line = i.next()                if line == 'Known torrents\n':                    break                t = decode_line(line)                if t is None:                    continue                infohash, t = t                if t.dlpath is None:                    raise BTFailure("Invalid state file contents")                t.state = QUEUED                self.queue.append(infohash)            while True:                line = i.next()                if line == 'End\n':                    break                t = decode_line(line)                if t is None:                    continue                infohash, t = t                if t.dlpath is None:                    t.state = ASKING_LOCATION                else:                    t.state = KNOWN                self.other_torrents.append(infohash)        except StopIteration:            raise BTFailure("Invalid state file contents")    def _queue_loop(self):        if self.doneflag.isSet():            return        self.rawserver.add_task(self._queue_loop, 20)        now = bttime()        if self.queue and self.starting_torrent is None:            mintime = now - self.config['next_torrent_time'] * 60            minratio = self.config['next_torrent_ratio'] / 100        else:            mintime = 0            minratio = self.config['last_torrent_ratio'] / 100            if not minratio:                return        for infohash in self.running_torrents:            t = self.torrents[infohash]            if t.state == RUN_QUEUED:                continue            totals = t.dl.get_total_transfer()            # not updated for remaining torrents if one is stopped, who cares            t.uptotal = t.uptotal_old + totals[0]            t.downtotal = t.downtotal_old + totals[1]            if t.finishtime is None or t.finishtime > now - 120:                continue

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -