contentmonster/src/contentmonster/classes/remotefile.py

105 lines
3.7 KiB
Python
Raw Normal View History

2022-09-19 18:05:58 +00:00
from ..const import STATUS_COMPLETE, STATUS_START
2021-11-20 14:40:07 +00:00
class RemoteFile:
"""Class describing the transfer status of a File to a Vessel"""
2021-11-25 15:31:49 +00:00
def __init__(self, fileobj, vessel, chunksize: int) -> None:
"""Initialize a new RemoteFile object
Args:
fileobj (classes.file.File): File object to transfer to a Vessel
vessel (classes.vessel.Vessel): Vessel to transfer the File to
chunksize (int): Size of a single Chunk to transfer
"""
2021-11-20 14:40:07 +00:00
self.file = fileobj
self.vessel = vessel
self.chunksize = chunksize
2021-11-25 15:31:49 +00:00
def getStatus(self) -> int:
"""Get the current transfer status
Returns:
int: Number of the last Chunk that was uploaded, or STATUS_COMPLETE
(-1) if a file upload is complete and waiting for finalization,
or STATUS_START (-2) if no Chunk has been uploaded yet
"""
# Get all files in the vessel's tempdir
2021-11-22 10:14:38 +00:00
ls = self.vessel.connection._listdir(self.vessel.tempdir)
files = [f for f in ls if f.startswith(self.file.uuid) and f.endswith(".part")]
2021-11-20 14:40:07 +00:00
2021-11-25 15:31:49 +00:00
# Find the file with the largest chunk number
count = -1
2021-11-20 14:40:07 +00:00
for f in files:
part = f.split("_")[1].split(".")[0]
2021-11-25 15:31:49 +00:00
if part == "complete": # If a reassembled file is found
if self.validateComplete(True): # and it is not broken
return STATUS_COMPLETE # the upload is complete
2021-11-20 14:40:07 +00:00
2021-11-25 15:31:49 +00:00
# Else save the chunk number if it is larger than the previous
try:
count = max(count, int(part))
except:
pass
2021-11-20 14:40:07 +00:00
2021-11-25 15:31:49 +00:00
# Find and return the largest non-corrupt chunk
2021-11-20 14:40:07 +00:00
while count >= 0:
if self.validateChunk(count):
return count
count -= 1
2021-11-25 15:31:49 +00:00
# If no (more) files exist, we are just getting started
2021-11-20 14:40:07 +00:00
return STATUS_START
2021-11-25 15:31:49 +00:00
def validateChunk(self, count: int) -> bool:
"""Validate that a Chunk was uploaded correctly
Args:
count (int): Chunk number to validate
Returns:
bool: True if file has been uploaded correctly, else False
"""
2021-11-20 14:40:07 +00:00
return self.vessel.connection.assertChunkComplete(self.getChunk(count))
2021-11-25 15:31:49 +00:00
def validateComplete(self, allow_retry: bool = False):
"""Validate that the complete File was reassembled correctly
Args:
allow_retry (bool, optional): If True, assume that compileComplete
failed for some other reason than corrupt Chunks, and only delete
compiled file, else clear entire temporary directory. Defaults to
False.
2021-11-20 14:40:07 +00:00
2021-11-25 15:31:49 +00:00
Returns:
bool: True if file was reassembled correctly, else False
"""
return self.vessel.connection.assertComplete(self, allow_retry)
def compileComplete(self) -> None:
"""Reassemble a complete File from the uploaded Chunks"""
2021-11-20 14:40:07 +00:00
self.vessel.connection.compileComplete(self)
2021-11-25 15:31:49 +00:00
def getChunk(self, count: int):
"""Get a Chunk of the source file
Args:
count (int): Number of the Chunk to generate
Returns:
classes.chunk.Chunk: A Chunk object containing the portion of the
2021-11-25 15:31:49 +00:00
File object beginning at (count * chunksize) bytes and ending at
((count + 1) * chunksize - 1) bytes, with chunksize taken from the
RemoteFile initialization value
"""
return self.file.getChunk(count, self.chunksize)
2021-11-25 18:03:58 +00:00
def finalizeUpload(self) -> None:
"""Move complete file to its final destination and clean up"""
2021-11-25 18:03:58 +00:00
self.vessel.connection.moveComplete(self)
self.vessel.connection.clearTempDir()