import logging from zope.interface import implements from lbrynet import interfaces from lbrynet.core.BlobInfo import BlobInfo from lbrynet.core.client.BlobRequester import BlobRequester from lbrynet.core.client.ConnectionManager import ConnectionManager from lbrynet.core.client.DownloadManager import DownloadManager from lbrynet.core.Error import InvalidBlobHashError from lbrynet.core.utils import is_valid_blobhash from twisted.python.failure import Failure from twisted.internet import defer log = logging.getLogger(__name__) class SingleBlobMetadataHandler(object): implements(interfaces.IMetadataHandler) def __init__(self, blob_hash, download_manager): self.blob_hash = blob_hash self.download_manager = download_manager ######## IMetadataHandler ######### def get_initial_blobs(self): log.debug("Returning the blob info") return defer.succeed([BlobInfo(self.blob_hash, 0, None)]) def final_blob_num(self): return 0 class SingleProgressManager(object): def __init__(self, finished_callback, download_manager): self.finished_callback = finished_callback self.finished = False self.download_manager = download_manager self._next_check_if_finished = None def start(self): from twisted.internet import reactor assert self._next_check_if_finished is None self._next_check_if_finished = reactor.callLater(0, self._check_if_finished) return defer.succeed(True) def stop(self): if self._next_check_if_finished is not None: self._next_check_if_finished.cancel() self._next_check_if_finished = None return defer.succeed(True) def _check_if_finished(self): from twisted.internet import reactor self._next_check_if_finished = None if self.finished is False: if self.stream_position() == 1: self.blob_downloaded(self.download_manager.blobs[0], 0) else: self._next_check_if_finished = reactor.callLater(1, self._check_if_finished) def stream_position(self): blobs = self.download_manager.blobs if blobs and blobs[0].is_validated(): return 1 return 0 def needed_blobs(self): blobs = self.download_manager.blobs assert len(blobs) == 1 return [b for b in blobs.itervalues() if not b.is_validated()] def blob_downloaded(self, blob, blob_num): from twisted.internet import reactor log.debug("The blob %s has been downloaded. Calling the finished callback", str(blob)) if self.finished is False: self.finished = True reactor.callLater(0, self.finished_callback, blob) class DummyBlobHandler(object): def __init__(self): pass def handle_blob(self, blob, blob_info): pass class StandaloneBlobDownloader(object): def __init__(self, blob_hash, blob_manager, peer_finder, rate_limiter, payment_rate_manager, wallet): self.blob_hash = blob_hash self.blob_manager = blob_manager self.peer_finder = peer_finder self.rate_limiter = rate_limiter self.payment_rate_manager = payment_rate_manager self.wallet = wallet self.download_manager = None self.finished_deferred = None def download(self): if not is_valid_blobhash(self.blob_hash): return defer.fail(Failure(InvalidBlobHashError(self.blob_hash))) def cancel_download(d): self.stop() self.finished_deferred = defer.Deferred(canceller=cancel_download) self.download_manager = DownloadManager(self.blob_manager, True) self.download_manager.blob_requester = BlobRequester(self.blob_manager, self.peer_finder, self.payment_rate_manager, self.wallet, self.download_manager) self.download_manager.blob_info_finder = SingleBlobMetadataHandler(self.blob_hash, self.download_manager) self.download_manager.progress_manager = SingleProgressManager(self._blob_downloaded, self.download_manager) self.download_manager.blob_handler = DummyBlobHandler() self.download_manager.wallet_info_exchanger = self.wallet.get_info_exchanger() self.download_manager.connection_manager = ConnectionManager( self, self.rate_limiter, [self.download_manager.blob_requester], [self.download_manager.wallet_info_exchanger] ) d = self.download_manager.start_downloading() d.addCallback(lambda _: self.finished_deferred) return d def stop(self): return self.download_manager.stop_downloading() def _blob_downloaded(self, blob): self.stop() if not self.finished_deferred.called: self.finished_deferred.callback(blob) def insufficient_funds(self, err): self.stop() if not self.finished_deferred.called: self.finished_deferred.errback(err)