Example #1
0
 def open_for_writing(self) -> HashBlobWriter:
     if os.path.exists(self.file_path):
         raise OSError(f"File already exists '{self.file_path}'")
     fut = asyncio.Future(loop=self.loop)
     writer = HashBlobWriter(self.blob_hash, self.get_length, fut)
     self.writers.append(writer)
     fut.add_done_callback(self.writer_finished(writer))
     return writer
Example #2
0
    def open_for_writing(self, peer):
        """
        open a blob file to be written by peer, supports concurrent
        writers, as long as they are from differnt peers.

        returns tuple of (writer, finished_deferred)

        writer - a file like object with a write() function, close() when finished
        finished_deferred - deferred that is fired when write is finished and returns
            a instance of itself as HashBlob
        """
        if not peer in self.writers:
            log.debug("Opening %s to be written by %s", str(self), str(peer))
            finished_deferred = defer.Deferred()
            writer = HashBlobWriter(self.get_length, self.writer_finished)
            self.writers[peer] = (writer, finished_deferred)
            return (writer, finished_deferred)
        log.warning("Tried to download the same file twice simultaneously from the same peer")
        return None, None
Example #3
0
    def get_blob_writer(
            self,
            peer_address: typing.Optional[str] = None,
            peer_port: typing.Optional[int] = None) -> HashBlobWriter:
        if (peer_address, peer_port) in self.writers and not self.writers[
            (peer_address, peer_port)].closed():
            raise OSError(
                f"attempted to download blob twice from {peer_address}:{peer_port}"
            )
        fut = asyncio.Future(loop=self.loop)
        writer = HashBlobWriter(self.blob_hash, self.get_length, fut)
        self.writers[(peer_address, peer_port)] = writer

        def remove_writer(_):
            if (peer_address, peer_port) in self.writers:
                del self.writers[(peer_address, peer_port)]

        fut.add_done_callback(remove_writer)

        def writer_finished_callback(finished: asyncio.Future):
            try:
                err = finished.exception()
                if err:
                    raise err
                verified_bytes = finished.result()
                while self.writers:
                    _, other = self.writers.popitem()
                    if other is not writer:
                        other.close_handle()
                self.save_verified_blob(verified_bytes)
            except (InvalidBlobHashError, InvalidDataError) as error:
                log.warning("writer error downloading %s: %s",
                            self.blob_hash[:8], str(error))
            except (DownloadCancelledError, asyncio.CancelledError,
                    asyncio.TimeoutError):
                pass

        fut.add_done_callback(writer_finished_callback)
        return writer