Exemplo n.º 1
0
    def __init__(self, url, callback):
        """
        If the URL conforms to a magnet link, the .torrent info is
        downloaded and returned to CALLBACK.
        """
        # _callback is called when the metadata is retrieved.
        self._callback = callback

        dn, xt, tr = self._parse_url(url)

        # _name is the unicode name suggested for the swarm.
        assert dn is None or isinstance(dn, unicode), "DN has invalid type: %s" % type(dn)
        self._name = dn

        # _info_hash is the 20 byte binary info hash that identifies
        # the swarm.
        assert isinstance(xt, str), "XT has invalid type: %s" % type(xt)
        assert len(xt) == 20, "XT has invalid length: %d" % len(xt)
        self._info_hash = xt

        # _tracker is an optional tracker address.
        self._tracker = tr

        # _swarm is a MiniBitTorrent.MiniSwarm instance that connects
        # to peers to retrieve the metadata.
        magnet_handler = MagnetHandler.get_instance()
        magnet_handler.add_magnet(self)
        self._swarm = MiniSwarm(self._info_hash, magnet_handler.get_raw_server(), self.metainfo_retrieved)
Exemplo n.º 2
0
class MagnetLink:
    def __init__(self, url, callback):
        """
        If the URL conforms to a magnet link, the .torrent info is
        downloaded and returned to CALLBACK.
        """
        # _callback is called when the metadata is retrieved.
        self._callback = callback

        dn, xt, tr = self._parse_url(url)

        # _name is the unicode name suggested for the swarm.
        assert dn is None or isinstance(dn, unicode), "DN has invalid type: %s" % type(dn)
        self._name = dn

        # _info_hash is the 20 byte binary info hash that identifies
        # the swarm.
        assert isinstance(xt, str), "XT has invalid type: %s" % type(xt)
        assert len(xt) == 20, "XT has invalid length: %d" % len(xt)
        self._info_hash = xt

        # _tracker is an optional tracker address.
        self._tracker = tr

        # _swarm is a MiniBitTorrent.MiniSwarm instance that connects
        # to peers to retrieve the metadata.
        magnet_handler = MagnetHandler.get_instance()
        magnet_handler.add_magnet(self)
        self._swarm = MiniSwarm(self._info_hash, magnet_handler.get_raw_server(), self.metainfo_retrieved)

    def get_infohash(self):
        return self._info_hash

    def get_name(self):
        return self._name

    def retrieve(self):
        """
        Start retrieving the metainfo
        
        Returns True when attempting to obtain the metainfo, in this
        case CALLBACK will always be called.  Otherwise False is
        returned, in this case CALLBACK will not be called.
        """
        if self._info_hash:
            # todo: catch the result from get_peers and call its stop
            # method.  note that this object does not yet contain a
            # stop method...
            dht = mainlineDHT.dht
            dht.get_peers(Id(self._info_hash), self._swarm.add_potential_peers)

            try:
                if self._tracker:
                    MiniTracker(self._swarm, self._tracker)
            except:
                print_exc()

            return True
        else:
            return False

    def metainfo_retrieved(self, metainfo, peers=[]):
        """
        Called when info part for metadata is retrieved.  If we have
        more metadata, we will add it at this point.

        PEERS optionally contains a list of valid BitTorrent peers,
        found during metadata download, to help bootstrap the
        download.
        """
        assert isinstance(metainfo, dict)
        assert isinstance(peers, list)
        if __debug__:
            for address in peers:
                assert isinstance(address[0], str)
                assert isinstance(address[1], int)

        # create metadata
        metadata = {"info":metainfo}
        if self._tracker:
            metadata["announce"] = self._tracker
        else:
            metadata["nodes"] = []
        if peers:
            metadata["initial peers"] = peers

        self._callback(metadata)
        self.close()

    def close(self):
        magnet_handler = MagnetHandler.get_instance()
        magnet_handler.remove_magnet(self)
        
        # close all MiniBitTorrent activities
        self._swarm.close()

    @staticmethod
    def _parse_url(url):
        # url must be a magnet link
        dn = None
        xt = None
        tr = None

        if DEBUG: print >> sys.stderr, time.asctime(),'-', "Magnet._parse_url()", url

        schema, netloc, path, query, fragment = urlsplit(url)
        if schema == "magnet":
            # magnet url's do not conform to regular url syntax (they
            # do not have a netloc.)  This causes path to contain the
            # query part.
            if "?" in path:
                pre, post = path.split("?", 1)
                if query:
                    query = "&".join((post, query))
                else:
                    query = post

            for key, value in parse_qsl(query):
                if key == "dn":
                    # convert to unicode
                    dn = value.decode()

                elif key == "xt" and value.startswith("urn:btih:"):
                    xt = unhexlify(value[9:49])

                elif key == "tr":
                    tr = value

            if DEBUG: print >> sys.stderr, time.asctime(),'-', "Magnet._parse_url() NAME:", dn
            if DEBUG: print >> sys.stderr, time.asctime(),'-', "Magnet._parse_url() HASH:", xt
            if DEBUG: print >> sys.stderr, time.asctime(),'-', "Magnet._parse_url() TRAC:", tr

        return (dn, xt, tr)