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

📄 rerequester.py

📁 BitTorrent(简称BT
💻 PY
字号:
# 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 Bram Cohen, Uoti Urpalafrom threading import Threadfrom socket import error, gethostbynamefrom random import random, randrangefrom binascii import b2a_hexfrom BitTorrent import versionfrom BitTorrent.platform import bttimefrom BitTorrent.zurllib import urlopen, quote, Requestfrom BitTorrent.btformats import check_peersfrom BitTorrent.bencode import bdecodefrom BitTorrent import BTFailure, INFO, WARNING, ERROR, CRITICALclass Rerequester(object):    def __init__(self, url, config, sched, howmany, connect, externalsched,            amount_left, up, down, port, myid, infohash, errorfunc, doneflag,            upratefunc, downratefunc, ever_got_incoming, diefunc, sfunc):        self.baseurl = url        self.infohash = infohash        self.peerid = None        self.wanted_peerid = myid        self.port = port        self.url = None        self.config = config        self.last = None        self.trackerid = None        self.announce_interval = 30 * 60        self.sched = sched        self.howmany = howmany        self.connect = connect        self.externalsched = externalsched        self.amount_left = amount_left        self.up = up        self.down = down        self.errorfunc = errorfunc        self.doneflag = doneflag        self.upratefunc = upratefunc        self.downratefunc = downratefunc        self.ever_got_incoming = ever_got_incoming        self.diefunc = diefunc        self.successfunc = sfunc        self.finish = False        self.current_started = None        self.fail_wait = None        self.last_time = None        self.previous_down = 0        self.previous_up = 0    def _makeurl(self, peerid, port):        return ('%s?info_hash=%s&peer_id=%s&port=%s&key=%s' %                (self.baseurl, quote(self.infohash), quote(peerid), str(port),                 b2a_hex(''.join([chr(randrange(256)) for i in xrange(4)]))))    def change_port(self, peerid, port):        self.wanted_peerid = peerid        self.port = port        self.last = None        self.trackerid = None        self._check()    def begin(self):        self.sched(self.begin, 60)        self._check()    def announce_finish(self):        self.finish = True        self._check()    def announce_stop(self):        self._announce(2)    def _check(self):        if self.current_started is not None:            if self.current_started <= bttime() - 58:                self.errorfunc(WARNING, "Tracker announce still not complete "                               "%d seconds after starting it" %                               int(bttime() - self.current_started))            return        if self.peerid is None:            self.peerid = self.wanted_peerid            self.url = self._makeurl(self.peerid, self.port)            self._announce(0)            return        if self.peerid != self.wanted_peerid:            self._announce(2)            self.peerid = None            self.previous_up = self.up()            self.previous_down = self.down()            return        if self.finish:            self.finish = False            self._announce(1)            return        if self.fail_wait is not None:            if self.last_time + self.fail_wait <= bttime():                self._announce()            return        if self.last_time > bttime() - self.config['rerequest_interval']:            return        if self.ever_got_incoming():            getmore = self.howmany() <= self.config['min_peers'] / 3        else:            getmore = self.howmany() < self.config['min_peers']        if getmore or bttime() - self.last_time > self.announce_interval:            self._announce()    def _announce(self, event=None):        self.current_started = bttime()        s = ('%s&uploaded=%s&downloaded=%s&left=%s' %            (self.url, str(self.up() - self.previous_up),             str(self.down() - self.previous_down), str(self.amount_left())))        if self.last is not None:            s += '&last=' + quote(str(self.last))        if self.trackerid is not None:            s += '&trackerid=' + quote(str(self.trackerid))        if self.howmany() >= self.config['max_initiate']:            s += '&numwant=0'        else:            s += '&compact=1'        if event is not None:            s += '&event=' + ['started', 'completed', 'stopped'][event]        Thread(target=self._rerequest, args=[s, self.peerid]).start()    # Must destroy all references that could cause reference circles    def cleanup(self):        self.sched = None        self.howmany = None        self.connect = None        self.externalsched = lambda *args: None        self.amount_left = None        self.up = None        self.down = None        self.errorfunc = None        self.upratefunc = None        self.downratefunc = None        self.ever_got_incoming = None        self.diefunc = None        self.successfunc = None    def _rerequest(self, url, peerid):        if self.config['ip']:            url += '&ip=' + gethostbyname(self.config['ip'])        request = Request(url)        request.add_header('User-Agent', 'BitTorrent/' + version)        if self.config['tracker_proxy']:            request.set_proxy(self.config['tracker_proxy'], 'http')        try:            h = urlopen(request)            data = h.read()            h.close()        # urllib2 can raise various crap that doesn't have a common base        # exception class especially when proxies are used, at least        # ValueError and stuff from httplib        except Exception, e:            def f(r='Problem connecting to tracker - ' + str(e)):                self._postrequest(errormsg=r, peerid=peerid)        else:            def f():                self._postrequest(data, peerid=peerid)        self.externalsched(f, 0)    def _fail(self):        if self.fail_wait is None:            self.fail_wait = 50        else:            self.fail_wait *= 1.4 + random() * .2        self.fail_wait = min(self.fail_wait,                                self.config['max_announce_retry_interval'])    def _postrequest(self, data=None, errormsg=None, peerid=None):        self.current_started = None        self.last_time = bttime()        if errormsg is not None:            self.errorfunc(WARNING, errormsg)            self._fail()            return        try:            r = bdecode(data)            check_peers(r)        except BTFailure, e:            if data != '':                self.errorfunc(ERROR, 'bad data from tracker - ' + str(e))            self._fail()            return        if r.has_key('failure reason'):            if self.howmany() > 0:                self.errorfunc(ERROR, 'rejected by tracker - ' +                               r['failure reason'])            else:                # sched shouldn't be strictly necessary                def die():                    self.diefunc(CRITICAL, "Aborting the torrent as it was "                    "rejected by the tracker while not connected to any peers."                    " Message from the tracker:     " + r['failure reason'])                self.sched(die, 0)            self._fail()        else:            self.fail_wait = None            if r.has_key('warning message'):                self.errorfunc(ERROR, 'warning from tracker - ' +                               r['warning message'])            self.announce_interval = r.get('interval', self.announce_interval)            self.config['rerequest_interval'] = r.get('min interval',                                            self.config['rerequest_interval'])            self.trackerid = r.get('tracker id', self.trackerid)            self.last = r.get('last')            p = r['peers']            peers = []            if type(p) == str:                for x in xrange(0, len(p), 6):                    ip = '.'.join([str(ord(i)) for i in p[x:x+4]])                    port = (ord(p[x+4]) << 8) | ord(p[x+5])                    peers.append((ip, port, None))            else:                for x in p:                    peers.append((x['ip'], x['port'], x.get('peer id')))            ps = len(peers) + self.howmany()            if ps < self.config['max_initiate']:                if self.doneflag.isSet():                    if r.get('num peers', 1000) - r.get('done peers', 0) > ps * 1.2:                        self.last = None                else:                    if r.get('num peers', 1000) > ps * 1.2:                        self.last = None            for x in peers:                self.connect((x[0], x[1]), x[2])            if peerid == self.wanted_peerid:                self.successfunc()            self._check()

⌨️ 快捷键说明

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