update: updated tor sync

This commit is contained in:
JOhn 2026-07-08 15:38:23 -04:00
parent 332a84f187
commit 43d47145a7
7 changed files with 134 additions and 35 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.ProfileObserver import ProfileObserver
from core.observers.TicketObserver import TicketObserver from core.observers.TicketObserver import TicketObserver
from core.controllers.ApplicationController import ApplicationController 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() application_version_observer = ApplicationVersionObserver()
client_observer = ClientObserver() client_observer = ClientObserver()
@ -15,70 +31,74 @@ ticket_observer = TicketObserver()
def setup_observers(update_status): def setup_observers(update_status):
relay = StatusRelay(update_status)
post_status = relay.post
profile_observer.subscribe( profile_observer.subscribe(
'created', lambda event: update_status('Profile Created')) 'created', lambda event: post_status('Profile Created'))
profile_observer.subscribe( profile_observer.subscribe(
'destroyed', lambda event: update_status('Profile destroyed')) 'destroyed', lambda event: post_status('Profile destroyed'))
# client_observer.subscribe( # client_observer.subscribe(
# 'synchronizing', lambda event: update_status('Sync in progress...')) # 'synchronizing', lambda event: update_status('Sync in progress...'))
client_observer.subscribe( client_observer.subscribe(
'synchronizing', lambda event: update_status(f'{event.subject if event.subject else "Sync in progress..."}')) 'synchronizing', lambda event: post_status(f'{event.subject if event.subject else "Sync in progress..."}'))
client_observer.subscribe( client_observer.subscribe(
'synchronized', lambda event: update_status('Sync complete')) 'synchronized', lambda event: post_status('Sync complete'))
client_observer.subscribe( client_observer.subscribe(
'updating', lambda event: update_status('Updating client...')) 'updating', lambda event: post_status('Updating client...'))
client_observer.subscribe('update_progressing', lambda event: update_status( client_observer.subscribe('update_progressing', lambda event: post_status(
f'Current progress: {event.meta.get('progress'):.2f}%')) f'Current progress: {event.meta.get('progress'):.2f}%'))
client_observer.subscribe('updated', lambda event: update_status( client_observer.subscribe('updated', lambda event: post_status(
'Restart client to apply update.')) 'Restart client to apply update.'))
client_observer.subscribe( client_observer.subscribe(
'custom_message', lambda event: update_status(f'{event.subject if event.subject else "Error, check logs"}')) 'custom_message', lambda event: post_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}')) 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}%')) 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}')) f'Downloaded {ApplicationController.get(event.subject.application_code).name}'))
connection_observer.subscribe('connecting', lambda event: update_status( connection_observer.subscribe('connecting', lambda event: post_status(
f'[{event.subject.get("attempt_count")}/{event.subject.get("maximum_number_of_attempts")}] Performing connection attempt...')) f'[{event.subject.get("attempt_count")}/{event.subject.get("maximum_number_of_attempts")}] Performing connection attempt...'))
connection_observer.subscribe('tor_bootstrapping', lambda event: update_status( connection_observer.subscribe('tor_bootstrapping', lambda event: post_status(
'Establishing Tor connection...')) 'Establishing Tor connection...'))
connection_observer.subscribe( connection_observer.subscribe(
'tor_bootstrap_progressing', lambda event: update_status(f'{event.subject if event.subject else "Tor Bootstrapping.."}')) 'tor_bootstrap_progressing', lambda event: post_status(f'{event.subject if event.subject else "Tor Bootstrapping.."}'))
# original replaced version: # original replaced version:
# connection_observer.subscribe('tor_bootstrap_progressing', lambda event: update_status( # connection_observer.subscribe('tor_bootstrap_progressing', lambda event: update_status(
# f'Bootstrapping Tor {event.meta.get('progress'):.2f}%')) # f'Bootstrapping Tor {event.meta.get('progress'):.2f}%'))
connection_observer.subscribe( connection_observer.subscribe(
'tor_bootstrapped', lambda event: update_status('Tor connection established.')) 'tor_bootstrapped', lambda event: post_status('Tor connection established.'))
client_observer.subscribe( client_observer.subscribe(
'custom_message', lambda event: update_status(f'{event.subject if event.subject else ""}')) 'custom_message', lambda event: post_status(f'{event.subject if event.subject else ""}'))
ticket_observer.subscribe('connecting', lambda event: update_status('Connecting to ticket server...')) ticket_observer.subscribe('connecting', lambda event: post_status('Connecting to ticket server...'))
ticket_observer.subscribe('sync_done', lambda event: update_status('Ticket prices synced.')) ticket_observer.subscribe('sync_done', lambda event: post_status('Ticket prices synced.'))
ticket_observer.subscribe('waiting', lambda event: update_status('Waiting for payment...')) ticket_observer.subscribe('waiting', lambda event: post_status('Waiting for payment...'))
ticket_observer.subscribe('paid', lambda event: update_status('Payment received.')) ticket_observer.subscribe('paid', lambda event: post_status('Payment received.'))
ticket_observer.subscribe('ticket_ready', lambda event: update_status('Ticket ready.')) ticket_observer.subscribe('ticket_ready', lambda event: post_status('Ticket ready.'))
ticket_observer.subscribe('used', lambda event: update_status('Ticket used.')) ticket_observer.subscribe('used', lambda event: post_status('Ticket used.'))
ticket_observer.subscribe('connection_error', lambda event: update_status('Ticket server connection error.')) ticket_observer.subscribe('connection_error', lambda event: post_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_output', lambda event: post_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('failed_input', lambda event: post_status(f'{event.subject if event.subject else ""}'))
ticket_observer.subscribe('unknown_error', lambda event: update_status('Unknown ticket error.')) ticket_observer.subscribe('unknown_error', lambda event: post_status('Unknown ticket error.'))
ticket_observer.subscribe('error', lambda event: update_status(f'Ticket error: {event.subject if event.subject else ""}')) ticket_observer.subscribe('error', lambda event: post_status(f'Ticket error: {event.subject if event.subject else ""}'))
return { return {
'status_relay': relay,
'application_version_observer': application_version_observer, 'application_version_observer': application_version_observer,
'client_observer': client_observer, 'client_observer': client_observer,
'connection_observer': connection_observer, 'connection_observer': connection_observer,

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.infrastructure.setup_observers import ticket_observer
from gui.v2.actions.profile_order import normalize_profile_order 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.Page import Page
from gui.v2.ui.pages.location_verification_page import LocationVerificationPage from gui.v2.ui.pages.location_verification_page import LocationVerificationPage
from gui.v2.ui.styles.styles import SCROLLBAR_CYAN_QSS from gui.v2.ui.styles.styles import SCROLLBAR_CYAN_QSS
@ -1008,9 +1009,14 @@ class MenuPage(Page):
if fast_mode: if fast_mode:
if not self.connection_manager.is_synced(): if not self.connection_manager.is_synced():
self.update_status.update_status('Syncing in progress..') self.update_status.update_status('Syncing in progress..')
self.update_status.sync() self.fast_registration_sync_worker = self._build_sync_worker()
self.update_status.worker_thread.sync_output.connect( 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.on_sync_complete_for_fast_registration)
self.fast_registration_sync_worker.start()
else: else:
self.custom_window.navigator.navigate("fast_registration") self.custom_window.navigator.navigate("fast_registration")
return return
@ -1021,12 +1027,18 @@ class MenuPage(Page):
self.custom_window.navigator.navigate("protocol") self.custom_window.navigator.navigate("protocol")
def on_sync_complete_for_fast_registration(self, available_locations, available_browsers, status, is_tor, locations, all_browsers): 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") self.custom_window.navigator.navigate("fast_registration")
else: else:
self.connection_manager.set_synced(False)
self.update_status.update_status( self.update_status.update_status(
'Sync failed. Please try again later.') 'Sync failed. Please try again later.')
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): def change_connect_button(self):
profile = ProfileController.get(int(self.reverse_id)) profile = ProfileController.get(int(self.reverse_id))
is_connected = self.connection_manager.is_profile_connected( is_connected = self.connection_manager.is_profile_connected(
@ -1163,9 +1175,11 @@ class MenuPage(Page):
self.update_status.update_status("Syncing...") self.update_status.update_status("Syncing...")
self.worker_thread = WorkerThread('SYNC') self.worker_thread = WorkerThread('SYNC')
self.worker_thread.finished.connect( 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 self.update_status.update_status("Sync failed. Please try again later."))
self.worker_thread.sync_output.connect( self.worker_thread.sync_output.connect(
self.update_status.update_values) self.update_status.update_values)
self.worker_thread.text_output.connect(
self.update_status.update_status)
self.worker_thread.start() self.worker_thread.start()
else: else:
self.update_status.update_status("Profile enable aborted") 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 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.ui.pages.Page import Page
from gui.v2.workers.worker_thread import WorkerThread from gui.v2.workers.worker_thread import WorkerThread
@ -82,10 +83,11 @@ class SyncScreen(Page):
self.worker_thread = WorkerThread('SYNC') self.worker_thread = WorkerThread('SYNC')
self.worker_thread.sync_output.connect(self.update_output) self.worker_thread.sync_output.connect(self.update_output)
self.worker_thread.text_output.connect(self.update_status.update_status)
self.worker_thread.start() self.worker_thread.start()
def update_output(self, available_locations, available_browsers, status, is_tor, locations, all_browsers): 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") self.custom_window.navigator.navigate("install_system_package")
install_page = self.custom_window.navigator.get_cached("install_system_package") install_page = self.custom_window.navigator.get_cached("install_system_package")
if install_page is not None: if install_page is not None:
@ -95,7 +97,8 @@ class SyncScreen(Page):
self.button_back.setEnabled(True) self.button_back.setEnabled(True)
return 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_go.setEnabled(True)
self.button_back.setEnabled(True) self.button_back.setEnabled(True)
self.update_status.update_status('An error occurred during sync') self.update_status.update_status('An error occurred during sync')

View file

@ -15,6 +15,8 @@ from core.models.session.SessionConnection import SessionConnection
from core.models.session.SessionProfile import SessionProfile from core.models.session.SessionProfile import SessionProfile
from core.models.system.SystemConnection import SystemConnection from core.models.system.SystemConnection import SystemConnection
from core.models.system.SystemProfile import SystemProfile 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 ( from gui.v2.infrastructure.setup_observers import (
client_observer, client_observer,
@ -228,22 +230,72 @@ class WorkerThread(QThread):
ConfigurationController.set_connection('tor') ConfigurationController.set_connection('tor')
else: else:
ConfigurationController.set_connection('system') ConfigurationController.set_connection('system')
self.check_for_update() sync_failed = False
def sync_status(event):
nonlocal sync_failed
message = event.subject if event.subject else "Sync in progress..."
message_text = str(message)
lowered = message_text.lower()
if "error" in lowered or "failed" in lowered or "failure" in lowered:
sync_failed = True
self.text_output.emit(message_text)
def sync_complete(event):
self.text_output.emit("Sync complete")
def connection_status(event):
subject = event.subject
if isinstance(subject, dict):
attempt = subject.get("attempt_count")
maximum = subject.get("maximum_number_of_attempts")
self.text_output.emit(
f"[{attempt}/{maximum}] Performing connection attempt...")
else:
self.text_output.emit("Performing connection attempt...")
sync_client_observer = ClientObserver()
sync_connection_observer = ConnectionObserver()
sync_client_observer.subscribe('synchronizing', sync_status)
sync_client_observer.subscribe('synchronized', sync_complete)
sync_connection_observer.subscribe('connecting', connection_status)
sync_connection_observer.subscribe(
'tor_bootstrapping', lambda event: self.text_output.emit('Establishing Tor connection...'))
sync_connection_observer.subscribe(
'tor_bootstrap_progressing', lambda event: self.text_output.emit(f'{event.subject if event.subject else "Tor Bootstrapping.."}'))
sync_connection_observer.subscribe(
'tor_bootstrapped', lambda event: self.text_output.emit('Tor connection established.'))
ClientController.sync(
client_observer=sync_client_observer,
connection_observer=sync_connection_observer)
if sync_failed:
self.sync_output.emit([], [], False, False, [], [])
self.finished.emit(False)
return
locations = LocationController.get_all() locations = LocationController.get_all()
browser = ApplicationVersionController.get_all() browser = ApplicationVersionController.get_all()
# print('the browser is: ', browser)
all_browser_versions = [ all_browser_versions = [
f"{browser.application_code}:{browser.version_number}" for browser in browser if browser.supported] f"{browser.application_code}:{browser.version_number}" for browser in browser if browser.supported]
all_location_codes = [ all_location_codes = [
f"{location.country_code}_{location.code}" for location in locations] 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( self.sync_output.emit(
all_location_codes, all_browser_versions, True, False, locations, browser) all_location_codes, all_browser_versions, True, False, locations, browser)
self.finished.emit(True)
except Exception as e: except Exception as e:
print(f'the error is: {e}') print(f'the error is: {e}')
self.sync_output.emit([], [], False, False, [], []) self.sync_output.emit([], [], False, False, [], [])
self.finished.emit(False)
def get_connection(self): def get_connection(self):
connection = ConfigurationController.get_connection() connection = ConfigurationController.get_connection()