Compare commits

...

2 commits

Author SHA1 Message Date
JOhn
fac64de65d update: updated gui status handling 2026-07-09 18:26:26 -04:00
JOhn
43d47145a7 update: updated tor sync 2026-07-08 15:38:23 -04:00
8 changed files with 153 additions and 70 deletions

0
gui/__main__.py Normal file → Executable file
View file

10
gui/v2/actions/sync_result.py Executable file
View file

@ -0,0 +1,10 @@
def is_valid_sync_payload(available_locations, available_browsers, status, locations, all_browsers):
if status is not True:
return False
if isinstance(all_browsers, bool):
return False
if not available_locations or not available_browsers:
return False
if not locations or not all_browsers:
return False
return True

View file

@ -5,6 +5,22 @@ from core.observers.InvoiceObserver import InvoiceObserver
from core.observers.ProfileObserver import ProfileObserver
from core.observers.TicketObserver import TicketObserver
from core.controllers.ApplicationController import ApplicationController
from PyQt6.QtCore import QObject, pyqtSignal
class StatusRelay(QObject):
status_requested = pyqtSignal(object, bool)
def __init__(self, update_status):
super().__init__()
self.update_status = update_status
self.status_requested.connect(self.apply_status)
def post(self, text, clear=False):
self.status_requested.emit(text, clear)
def apply_status(self, text, clear=False):
self.update_status(text, clear=clear)
application_version_observer = ApplicationVersionObserver()
client_observer = ClientObserver()
@ -14,71 +30,64 @@ profile_observer = ProfileObserver()
ticket_observer = TicketObserver()
def observer_message(topic, event):
subject = getattr(event, 'subject', None)
meta = getattr(event, 'meta', None)
if subject is not None:
return str(subject)
if meta:
return str(meta)
return str(topic)
def subscribe_observer_messages(observer, post_status):
for attr in dir(observer):
if not attr.startswith('on_'):
continue
callbacks = getattr(observer, attr, None)
if not isinstance(callbacks, list):
continue
topic = attr[3:]
observer.subscribe(
topic,
lambda event, topic=topic: post_status(observer_message(topic, event)))
def setup_observers(update_status):
relay = StatusRelay(update_status)
post_status = relay.post
profile_observer.subscribe(
'created', lambda event: update_status('Profile Created'))
'created', lambda event: post_status('Profile Created'))
profile_observer.subscribe(
'destroyed', lambda event: update_status('Profile destroyed'))
'destroyed', lambda event: post_status('Profile destroyed'))
# client_observer.subscribe(
# 'synchronizing', lambda event: update_status('Sync in progress...'))
subscribe_observer_messages(client_observer, post_status)
client_observer.subscribe(
'synchronizing', lambda event: update_status(f'{event.subject if event.subject else "Sync in progress..."}'))
client_observer.subscribe(
'synchronized', lambda event: update_status('Sync complete'))
client_observer.subscribe(
'updating', lambda event: update_status('Updating client...'))
client_observer.subscribe('update_progressing', lambda event: update_status(
f'Current progress: {event.meta.get('progress'):.2f}%'))
client_observer.subscribe('updated', lambda event: update_status(
'Restart client to apply update.'))
client_observer.subscribe(
'custom_message', lambda event: update_status(f'{event.subject if event.subject else "Error, check logs"}'))
application_version_observer.subscribe('downloading', lambda event: update_status(
application_version_observer.subscribe('downloading', lambda event: post_status(
f'Downloading {ApplicationController.get(event.subject.application_code).name}'))
application_version_observer.subscribe('download_progressing', lambda event: update_status(
application_version_observer.subscribe('download_progressing', lambda event: post_status(
f'Downloading {ApplicationController.get(event.subject.application_code).name} {event.meta.get('progress'):.2f}%'))
application_version_observer.subscribe('downloaded', lambda event: update_status(
application_version_observer.subscribe('downloaded', lambda event: post_status(
f'Downloaded {ApplicationController.get(event.subject.application_code).name}'))
connection_observer.subscribe('connecting', lambda event: update_status(
f'[{event.subject.get("attempt_count")}/{event.subject.get("maximum_number_of_attempts")}] Performing connection attempt...'))
subscribe_observer_messages(connection_observer, post_status)
connection_observer.subscribe('tor_bootstrapping', lambda event: update_status(
'Establishing Tor connection...'))
connection_observer.subscribe(
'tor_bootstrap_progressing', lambda event: update_status(f'{event.subject if event.subject else "Tor Bootstrapping.."}'))
# original replaced version:
# connection_observer.subscribe('tor_bootstrap_progressing', lambda event: update_status(
# f'Bootstrapping Tor {event.meta.get('progress'):.2f}%'))
connection_observer.subscribe(
'tor_bootstrapped', lambda event: update_status('Tor connection established.'))
client_observer.subscribe(
'custom_message', lambda event: update_status(f'{event.subject if event.subject else ""}'))
ticket_observer.subscribe('connecting', lambda event: update_status('Connecting to ticket server...'))
ticket_observer.subscribe('sync_done', lambda event: update_status('Ticket prices synced.'))
ticket_observer.subscribe('waiting', lambda event: update_status('Waiting for payment...'))
ticket_observer.subscribe('paid', lambda event: update_status('Payment received.'))
ticket_observer.subscribe('ticket_ready', lambda event: update_status('Ticket ready.'))
ticket_observer.subscribe('used', lambda event: update_status('Ticket used.'))
ticket_observer.subscribe('connection_error', lambda event: update_status('Ticket server connection error.'))
ticket_observer.subscribe('failed_output', lambda event: update_status(f'{event.subject if event.subject else ""}'))
ticket_observer.subscribe('failed_input', lambda event: update_status(f'{event.subject if event.subject else ""}'))
ticket_observer.subscribe('unknown_error', lambda event: update_status('Unknown ticket error.'))
ticket_observer.subscribe('error', lambda event: update_status(f'Ticket error: {event.subject if event.subject else ""}'))
ticket_observer.subscribe('connecting', lambda event: post_status('Connecting to ticket server...'))
ticket_observer.subscribe('sync_done', lambda event: post_status('Ticket prices synced.'))
ticket_observer.subscribe('waiting', lambda event: post_status('Waiting for payment...'))
ticket_observer.subscribe('paid', lambda event: post_status('Payment received.'))
ticket_observer.subscribe('ticket_ready', lambda event: post_status('Ticket ready.'))
ticket_observer.subscribe('used', lambda event: post_status('Ticket used.'))
ticket_observer.subscribe('connection_error', lambda event: post_status('Ticket server connection error.'))
ticket_observer.subscribe('failed_output', lambda event: post_status(f'{event.subject if event.subject else ""}'))
ticket_observer.subscribe('failed_input', lambda event: post_status(f'{event.subject if event.subject else ""}'))
ticket_observer.subscribe('unknown_error', lambda event: post_status('Unknown ticket error.'))
ticket_observer.subscribe('error', lambda event: post_status(f'Ticket error: {event.subject if event.subject else ""}'))
return {
'status_relay': relay,
'application_version_observer': application_version_observer,
'client_observer': client_observer,
'connection_observer': connection_observer,

View file

@ -576,11 +576,9 @@ class EditorPage(Page):
def on_sync_complete_for_edit_profile(self, available_locations, available_browsers, status, is_tor, locations, all_browsers):
if status:
self.update_status.update_status('Sync complete.')
self.extraccion()
else:
self.update_status.update_status(
'Sync failed. Please try again later.')
self.connection_manager.set_synced(False)
def show_previous_value(self, key: str, index: int, parameters: dict) -> None:
if key == 'browser' or key == 'location':

View file

@ -21,6 +21,7 @@ from core.models.system.SystemProfile import SystemProfile
from gui.v2.infrastructure.setup_observers import ticket_observer
from gui.v2.actions.profile_order import normalize_profile_order
from gui.v2.actions.sync_result import is_valid_sync_payload
from gui.v2.ui.pages.Page import Page
from gui.v2.ui.pages.location_verification_page import LocationVerificationPage
from gui.v2.ui.styles.styles import SCROLLBAR_CYAN_QSS
@ -1008,9 +1009,14 @@ class MenuPage(Page):
if fast_mode:
if not self.connection_manager.is_synced():
self.update_status.update_status('Syncing in progress..')
self.update_status.sync()
self.update_status.worker_thread.sync_output.connect(
self.fast_registration_sync_worker = self._build_sync_worker()
self.fast_registration_sync_worker.text_output.connect(
self.update_status.update_status)
self.fast_registration_sync_worker.sync_output.connect(
self.update_status.update_values)
self.fast_registration_sync_worker.sync_output.connect(
self.on_sync_complete_for_fast_registration)
self.fast_registration_sync_worker.start()
else:
self.custom_window.navigator.navigate("fast_registration")
return
@ -1021,11 +1027,15 @@ class MenuPage(Page):
self.custom_window.navigator.navigate("protocol")
def on_sync_complete_for_fast_registration(self, available_locations, available_browsers, status, is_tor, locations, all_browsers):
if status:
if is_valid_sync_payload(available_locations, available_browsers, status, locations, all_browsers):
self.custom_window.navigator.navigate("fast_registration")
else:
self.update_status.update_status(
'Sync failed. Please try again later.')
self.connection_manager.set_synced(False)
def _build_sync_worker(self):
if self.update_status.get_current_connection() == 'tor':
return WorkerThread('SYNC_TOR')
return WorkerThread('SYNC')
def change_connect_button(self):
profile = ProfileController.get(int(self.reverse_id))
@ -1067,8 +1077,7 @@ class MenuPage(Page):
if status:
self.custom_window.navigator.navigate("editor")
else:
self.update_status.update_status(
'Sync failed. Please try again later.')
self.connection_manager.set_synced(False)
def settings_gui(self):
self.custom_window.navigator.navigate("settings")
@ -1163,9 +1172,11 @@ class MenuPage(Page):
self.update_status.update_status("Syncing...")
self.worker_thread = WorkerThread('SYNC')
self.worker_thread.finished.connect(
lambda: self.handle_sync_after_verification(profile_id))
lambda ok: self.handle_sync_after_verification(profile_id) if ok else None)
self.worker_thread.sync_output.connect(
self.update_status.update_values)
self.worker_thread.text_output.connect(
self.update_status.update_status)
self.worker_thread.start()
else:
self.update_status.update_status("Profile enable aborted")

View file

@ -5,6 +5,7 @@ from PyQt6.QtGui import QPixmap
from core.controllers.ClientController import ClientController
from gui.v2.actions.sync_result import is_valid_sync_payload
from gui.v2.ui.pages.Page import Page
from gui.v2.workers.worker_thread import WorkerThread
@ -82,10 +83,11 @@ class SyncScreen(Page):
self.worker_thread = WorkerThread('SYNC')
self.worker_thread.sync_output.connect(self.update_output)
self.worker_thread.text_output.connect(self.update_status.update_status)
self.worker_thread.start()
def update_output(self, available_locations, available_browsers, status, is_tor, locations, all_browsers):
if isinstance(all_browsers, bool) and not all_browsers:
if status is True and isinstance(all_browsers, bool) and not all_browsers:
self.custom_window.navigator.navigate("install_system_package")
install_page = self.custom_window.navigator.get_cached("install_system_package")
if install_page is not None:
@ -95,14 +97,12 @@ class SyncScreen(Page):
self.button_back.setEnabled(True)
return
if status is False:
if not is_valid_sync_payload(available_locations, available_browsers, status, locations, all_browsers):
self.connection_manager.set_synced(False)
self.button_go.setEnabled(True)
self.button_back.setEnabled(True)
self.update_status.update_status('An error occurred during sync')
return
self.update_status.update_status('Sync complete')
update_available = ClientController.can_be_updated()
if update_available:

View file

@ -15,6 +15,8 @@ from core.models.session.SessionConnection import SessionConnection
from core.models.session.SessionProfile import SessionProfile
from core.models.system.SystemConnection import SystemConnection
from core.models.system.SystemProfile import SystemProfile
from core.observers.ClientObserver import ClientObserver
from core.observers.ConnectionObserver import ConnectionObserver
from gui.v2.infrastructure.setup_observers import (
client_observer,
@ -222,28 +224,81 @@ class WorkerThread(QThread):
finally:
self.finished.emit(True)
def _emit_observer_message(self, topic, event):
subject = getattr(event, 'subject', None)
meta = getattr(event, 'meta', None)
if subject is not None:
self.text_output.emit(str(subject))
elif meta:
self.text_output.emit(str(meta))
else:
self.text_output.emit(str(topic))
def _subscribe_observer_messages(self, observer, skip_topics=None):
skip_topics = skip_topics or set()
for attr in dir(observer):
if not attr.startswith('on_'):
continue
callbacks = getattr(observer, attr, None)
if not isinstance(callbacks, list):
continue
topic = attr[3:]
if topic in skip_topics:
continue
observer.subscribe(
topic,
lambda event, topic=topic: self._emit_observer_message(topic, event))
def sync(self):
try:
if self.action == 'SYNC_TOR':
ConfigurationController.set_connection('tor')
else:
ConfigurationController.set_connection('system')
self.check_for_update()
sync_succeeded = False
def sync_complete(event):
nonlocal sync_succeeded
sync_succeeded = True
self._emit_observer_message('synchronized', event)
sync_client_observer = ClientObserver()
sync_connection_observer = ConnectionObserver()
self._subscribe_observer_messages(
sync_client_observer, {'synchronized'})
self._subscribe_observer_messages(sync_connection_observer)
sync_client_observer.subscribe('synchronized', sync_complete)
ClientController.sync(
client_observer=sync_client_observer,
connection_observer=sync_connection_observer)
if not sync_succeeded:
self.sync_output.emit([], [], False, False, [], [])
self.finished.emit(False)
return
locations = LocationController.get_all()
browser = ApplicationVersionController.get_all()
# print('the browser is: ', browser)
all_browser_versions = [
f"{browser.application_code}:{browser.version_number}" for browser in browser if browser.supported]
all_location_codes = [
f"{location.country_code}_{location.code}" for location in locations]
if not all_location_codes or not all_browser_versions or not locations or not browser:
self.sync_output.emit([], [], False, False, [], [])
self.finished.emit(False)
return
self.sync_output.emit(
all_location_codes, all_browser_versions, True, False, locations, browser)
self.finished.emit(True)
except Exception as e:
print(f'the error is: {e}')
self.sync_output.emit([], [], False, False, [], [])
self.finished.emit(False)
def get_connection(self):
connection = ConfigurationController.get_connection()