from core.observers.ApplicationVersionObserver import ApplicationVersionObserver from core.observers.ClientObserver import ClientObserver from core.observers.ConnectionObserver import ConnectionObserver from core.observers.InvoiceObserver import InvoiceObserver from core.observers.ProfileObserver import ProfileObserver from core.services.encrypted_proxy.observer_helpers import create_ui_state, create_event_handlers from core.controllers.ApplicationController import ApplicationController from cli.killswitch_monitor import drop_state, tunnel_state from cli.ui import progress_bar from cli.helpers import sanitize_profile import pprint # ── Observer instances ──────────────────────────────────────────────────────── application_version_observer = ApplicationVersionObserver() client_observer = ClientObserver() connection_observer = ConnectionObserver() invoice_observer = InvoiceObserver() profile_observer = ProfileObserver() # ── Shared UI state (used by observer_helpers) ──────────────────────────────── _ui_state = create_ui_state() # Public refs for profile.py to access monitor and timer def get_ui_state(): return _ui_state # ── Connection event handlers (from core) ───────────────────────────────────── _handlers = create_event_handlers(_ui_state, drop_state, tunnel_state) connection_observer.subscribe('connecting', _handlers['on_connecting']) connection_observer.subscribe('connected', _handlers['on_connected']) connection_observer.subscribe('connected_token', _handlers['on_connected_token']) connection_observer.subscribe('disconnected', _handlers['on_disconnected']) connection_observer.subscribe('error', _handlers['on_error']) # ── Tor events ──────────────────────────────────────────────────────────────── def _on_tor_bootstrapping(event): from cli.ui import Spinner _ui_state['spinner'] = Spinner("Starting Tor...") _ui_state['spinner'].start() def _on_tor_bootstrap_progressing(event): pct = int(event.meta.get("progress", 0)) progress_bar(pct, 100, "Tor bootstrap") def _on_tor_bootstrapped(event): from cli.ui import label_ok if _ui_state['spinner']: _ui_state['spinner'].stop() _ui_state['spinner'] = None print() label_ok("Tor ready") connection_observer.subscribe('tor_bootstrapping', _on_tor_bootstrapping) connection_observer.subscribe('tor_bootstrap_progressing', _on_tor_bootstrap_progressing) connection_observer.subscribe('tor_bootstrapped', _on_tor_bootstrapped) # ── Application version events ──────────────────────────────────────────────── application_version_observer.subscribe( 'downloading', lambda event: print( f'Downloading {ApplicationController.get(event.subject.application_code).name}, ' f'version {event.subject.version_number}...' ) ) application_version_observer.subscribe( 'download_progressing', lambda event: print(f'Current progress: {event.meta.get("progress"):.2f}%', flush=True, end='\r') ) application_version_observer.subscribe('downloaded', lambda event: print('\n')) # ── Client events ───────────────────────────────────────────────────────────── client_observer.subscribe('synchronizing', lambda event: print('Synchronizing...\n')) client_observer.subscribe('updating', lambda event: print('Updating client...')) client_observer.subscribe('update_progressing', lambda event: print(f'Current progress: {event.meta.get("progress"):.2f}%', flush=True, end='\r')) client_observer.subscribe('updated', lambda event: print('\n')) # ── Invoice events ──────────────────────────────────────────────────────────── invoice_observer.subscribe('retrieved', lambda event: print(f'\n{pprint.pp(event.subject)}\n')) invoice_observer.subscribe('processing', lambda event: print('A payment has been detected and is being verified...\n')) invoice_observer.subscribe('settled', lambda event: print('The payment has been successfully verified.\n')) # ── Profile events ──────────────────────────────────────────────────────────── profile_observer.subscribe('created', lambda event: pprint.pp((sanitize_profile(event.subject), 'Created'))) profile_observer.subscribe('destroyed', lambda event: pprint.pp((sanitize_profile(event.subject), 'Destroyed'))) profile_observer.subscribe('disabled', lambda event: pprint.pp((sanitize_profile(event.subject), 'Disabled')) if event.meta.get('explicitly') else None) profile_observer.subscribe('enabled', lambda event: pprint.pp((sanitize_profile(event.subject), 'Enabled')))