From 2ee1d50a13082c830bee1f8142922a18bbf124e1 Mon Sep 17 00:00:00 2001
From: codeking <t@libertyoceanhorizons.com>
Date: Sun, 8 Dec 2024 02:59:36 +0100
Subject: [PATCH] Implement additional application download events

---
 .../ApplicationVersionController.py           | 25 +++++++++++++++++--
 core/observers/ApplicationVersionObserver.py  |  3 +++
 main.py                                       |  5 +++-
 3 files changed, 30 insertions(+), 3 deletions(-)

diff --git a/core/controllers/ApplicationVersionController.py b/core/controllers/ApplicationVersionController.py
index c5549f2..091ba61 100644
--- a/core/controllers/ApplicationVersionController.py
+++ b/core/controllers/ApplicationVersionController.py
@@ -71,12 +71,31 @@ class ApplicationVersionController:
 
         if response.status_code == 200:
 
-            file_hash = ApplicationVersionController.__calculate_file_hash(BytesIO(response.content))
+            response_size = int(response.headers.get('Content-Length', 0))
+            response_buffer = BytesIO()
+
+            block_size = 1024
+            bytes_written = 0
+
+            for data in response.iter_content(block_size):
+
+                bytes_written += len(data)
+                response_buffer.write(data)
+                progress = (bytes_written / response_size) * 100 if response_size > 0 else 0
+
+                application_version_observer.notify('download_progress', application_version, dict(
+                    progress=progress
+                ))
+
+            application_version_observer.notify('download_finished', application_version)
+            response_buffer.seek(0)
+
+            file_hash = ApplicationVersionController.__calculate_file_hash(response_buffer)
 
             if file_hash != application_version.file_hash:
                 raise FileIntegrityError('Application version file integrity could not be verified.')
 
-            with tarfile.open(fileobj=BytesIO(response.content), mode = 'r:gz') as tar_file:
+            with tarfile.open(fileobj=response_buffer, mode = 'r:gz') as tar_file:
 
                 tar_file.extractall(application_version.get_installation_path())
                 tar_file.close()
@@ -100,4 +119,6 @@ class ApplicationVersionController:
             hasher.update(buffer)
             buffer = file.read(65536)
 
+        file.seek(0)
+
         return hasher.hexdigest()
diff --git a/core/observers/ApplicationVersionObserver.py b/core/observers/ApplicationVersionObserver.py
index 060beab..0a48613 100644
--- a/core/observers/ApplicationVersionObserver.py
+++ b/core/observers/ApplicationVersionObserver.py
@@ -4,4 +4,7 @@ from core.observers.BaseObserver import BaseObserver
 class ApplicationVersionObserver(BaseObserver):
 
     def __init__(self):
+
         self.on_downloading = []
+        self.on_download_progress = []
+        self.on_download_finished = []
diff --git a/main.py b/main.py
index 0bc9952..7341423 100644
--- a/main.py
+++ b/main.py
@@ -36,7 +36,10 @@ if __name__ == '__main__':
     invoice_observer = InvoiceObserver()
     profile_observer = ProfileObserver()
 
-    application_version_observer.subscribe('downloading', lambda event: print(f'Downloading {ApplicationController.get(event.subject.application_code).name}, version {event.subject.version_number}...\n'))
+    application_version_observer.subscribe('downloading', lambda event: print(f'Downloading {ApplicationController.get(event.subject.application_code).name}, version {event.subject.version_number}...'))
+    application_version_observer.subscribe('download_progress', lambda event: print(f'Current progress: {event.meta.get('progress'):.2f}%', flush=True, end='\r'))
+    application_version_observer.subscribe('download_finished', lambda event: print('\n'))
+
     client_observer.subscribe('synchronizing', lambda event: print('Synchronizing...\n'))
     connection_observer.subscribe('connecting', lambda event: print(f'[{event.subject.get("attempt_count")}/{event.subject.get("maximum_number_of_attempts")}] Performing connection attempt...\n'))