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
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
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