From 782a18f8f14698b33d23dae677a153adc1985f6a Mon Sep 17 00:00:00 2001 From: derrod Date: Wed, 11 Aug 2021 09:16:06 +0200 Subject: [PATCH] [models] Add type hints and migrate downloader models to dataclasses --- legendary/models/downloading.py | 286 +++++++++++++++++--------------- 1 file changed, 150 insertions(+), 136 deletions(-) diff --git a/legendary/models/downloading.py b/legendary/models/downloading.py index b538090..6d1da6b 100644 --- a/legendary/models/downloading.py +++ b/legendary/models/downloading.py @@ -1,165 +1,179 @@ # coding: utf-8 +from dataclasses import dataclass +from typing import Union -class DownloaderTask: - def __init__(self, url=None, chunk_guid=None, shm=None, kill=False): - self.url = url - self.guid = chunk_guid - self.shm = shm - self.kill = kill - - -class DownloaderTaskResult: - def __init__(self, success, chunk_guid, shm, url, size=None, - compressed_size=None, time_delta=None): - self.success = success - self.shm = shm - self.size = size - self.compressed_size = compressed_size - self.guid = chunk_guid - self.time_delta = time_delta - self.url = url - - -class WriterTask: - """ - Writing task for FileWorker, including some metadata that is required. - """ - - def __init__(self, filename, chunk_offset=0, chunk_size=0, chunk_guid=None, close=False, - shared_memory=None, cache_file='', old_file='', release_memory=False, rename=False, - empty=False, kill=False, delete=False, old_filename='', fopen=False, silent=False): - self.filename = filename - self.empty = empty - self.shm = shared_memory - self.chunk_offset = chunk_offset - self.chunk_size = chunk_size - self.chunk_guid = chunk_guid - self.release_memory = release_memory - - # reading from a cached chunk instead of memory - self.cache_file = cache_file - self.old_file = old_file - self.open = fopen - self.close = close - self.delete = delete - self.rename = rename - self.old_filename = old_filename - - self.silent = silent # disable logging - self.kill = kill # final task for worker (quit) - - -class WriterTaskResult: - def __init__(self, success, filename='', chunk_guid='', - release_memory=False, shm=None, size=0, - kill=False, closed=False, time_delta=None): - self.success = success - self.filename = filename - self.chunk_guid = chunk_guid - self.release_memory = release_memory - self.shm = shm - self.size = size - self.kill = kill - self.closed = closed - self.time_delta = time_delta - - -class UIUpdate: - """ - Status update object sent from the manager to the CLI/GUI to update status indicators - """ - - def __init__(self, progress, download_speed, write_speed, read_speed, - memory_usage, current_filename=''): - self.progress = progress - self.download_speed = download_speed - self.write_speed = write_speed - self.read_speed = read_speed - self.current_filename = current_filename - self.memory_usage = memory_usage +from .manifest import ManifestComparison +@dataclass class SharedMemorySegment: """ Segment of the shared memory used for one Chunk """ - - def __init__(self, offset=0, end=1024 * 1024): - self.offset = offset - self.end = end + offset: int = 0 + end: int = 1024 * 1024 @property def size(self): return self.end - self.offset +@dataclass +class DownloaderTask: + """ + Task submitted to the download worker + """ + url: Union[str, None] = None + chunk_guid: Union[int, None] = None + shm: Union[SharedMemorySegment, None] = None + kill: bool = False + + +@dataclass +class DownloaderTaskResult: + """ + Result of DownloaderTask provided by download workers + """ + success: bool + chunk_guid: int + shm: SharedMemorySegment + url: str + size: Union[int, None] = None + compressed_size: Union[int, None] = None + time_delta: Union[int, None] = None + + +@dataclass class ChunkTask: - def __init__(self, chunk_guid, chunk_offset=0, chunk_size=0, cleanup=False, chunk_file=None): - """ - Download manager chunk task - - :param chunk_guid: GUID of chunk - :param cleanup: whether or not this chunk can be removed from disk/memory after it has been written - :param chunk_offset: Offset into file or shared memory - :param chunk_size: Size to read from file or shared memory - :param chunk_file: Either cache or existing game file this chunk is read from if not using shared memory - """ - self.chunk_guid = chunk_guid - self.cleanup = cleanup - self.chunk_offset = chunk_offset - self.chunk_size = chunk_size - self.chunk_file = chunk_file + """ + A task describing a single read of a (partial) chunk from memory or an existing file + """ + chunk_guid: int + chunk_offset: int = 0 + chunk_size: int = 0 + # Whether this chunk can be removed from memory/disk after having been written + cleanup: bool = False + # Path to the file the chunk is read from (if not from memory) + chunk_file: Union[str, None] = None +@dataclass class FileTask: - def __init__(self, filename, delete=False, empty=False, fopen=False, close=False, - rename=False, temporary_filename=None, silent=False): - """ - Download manager Task for a file - - :param filename: name of the file - :param delete: if this is a file to be deleted, if rename is true, delete filename before renaming - :param empty: if this is an empty file that just needs to be "touch"-ed (may not have chunk tasks) - - :param temporary_filename: If rename is true: Filename to rename from. - """ - self.filename = filename - self.delete = delete - self.empty = empty - self.open = fopen - self.close = close - self.rename = rename - self.temporary_filename = temporary_filename - self.silent = silent + """ + A task describing some operation on the filesystem + """ + filename: str + # just create a 0-byte file + empty: bool = False + open: bool = False + close: bool = False + rename: bool = False + # Deletes the file, if rename is true, this will remove an existing file with the target name + delete: bool = False + silent: bool = False + # If rename is true, this is the name of the file to be renamed + temporary_filename: Union[str, None] = None @property def is_reusing(self): return self.temporary_filename is not None +@dataclass +class WriterTask: + """ + Task for FileWriter worker process, describing an operation on the filesystem + """ + filename: str + + chunk_offset: int = 0 + chunk_size: int = 0 + chunk_guid: Union[int, None] = None + + # Just create an empty file + empty: bool = False + # Whether shared memory segment shall be released back to the pool on completion + release_memory: bool = False + shared_memory: Union[SharedMemorySegment, None] = None + + # File to read old chunk from, disk chunk cache or old game file + old_file: Union[str, None] = None + cache_file: Union[str, None] = None + + open: bool = False + close: bool = False + delete: bool = False + # Do not log deletion failures + silent: bool = False + + rename: bool = False + # Filename to rename from + old_filename: Union[str, None] = None + + # Instruct worker to terminate + kill: bool = False + + +@dataclass +class WriterTaskResult: + """ + Result from the FileWriter worker + """ + success: bool + filename: Union[str, None] = None + size: int = 0 + chunk_guid: Union[int, None] = None + + shared_memory: Union[SharedMemorySegment, None] = None + release_memory: bool = False + closed: bool = False + time_delta: Union[float, None] = None + + # Worker terminated, instructs results handler to also stop + kill: bool = False + + +@dataclass +class UIUpdate: + """ + Status update object sent from the manager to the CLI/GUI to update status indicators + """ + progress: float + download_speed: float + write_speed: float + read_speed: float + memory_usage: float + current_filename: Union[str, None] = None + + +@dataclass class AnalysisResult: - def __init__(self): - self.dl_size = 0 - self.uncompressed_dl_size = 0 - self.install_size = 0 - self.reuse_size = 0 - self.biggest_file_size = 0 - self.unchanged_size = 0 - self.biggest_chunk = 0 - self.min_memory = 0 - self.num_chunks = 0 - self.num_chunks_cache = 0 - self.num_files = 0 - self.removed = 0 - self.added = 0 - self.changed = 0 - self.unchanged = 0 - self.manifest_comparison = None + """ + Result of processing a manifest for downloading + """ + dl_size: int = 0 + uncompressed_dl_size: int = 0 + install_size: int = 0 + reuse_size: int = 0 + biggest_file_size: int = 0 + unchanged_size: int = 0 + biggest_chunk: int = 0 + min_memory: int = 0 + num_chunks: int = 0 + num_chunks_cache: int = 0 + num_files: int = 0 + removed: int = 0 + added: int = 0 + changed: int = 0 + unchanged: int = 0 + manifest_comparison: Union[ManifestComparison, None] = None +@dataclass class ConditionCheckResult: - """Result object used in Core to identify problems that would prevent an installation from succeeding""" - def __init__(self, failures=None, warnings=None): - self.failures = failures - self.warnings = warnings + """ + Result of install condition checks + """ + failures: Union[list, None] = None + warnings: Union[list, None] = None