sp-hydra-veil-core/core/controllers/ClientController.py

177 lines
6.8 KiB
Python

from core.services.sync.sync_service import coordinate_cache_sync
from core.Constants import Constants
from core.Errors import UnknownClientPathError, UnknownClientVersionError, CommandNotFoundError
from core.controllers.ApplicationController import ApplicationController
from core.controllers.ApplicationVersionController import ApplicationVersionController
from core.controllers.ClientVersionController import ClientVersionController
from core.controllers.ConfigurationController import ConfigurationController
from core.controllers.LocationController import LocationController
from core.controllers.OperatorController import OperatorController
from core.controllers.SubscriptionPlanController import SubscriptionPlanController
from core.observers.ClientObserver import ClientObserver
from core.observers.ConnectionObserver import ConnectionObserver
from typing import Optional
import os
import pathlib
import re
import shutil
import subprocess
class ClientController:
@staticmethod
def get_working_directory():
return str(pathlib.Path(__file__).resolve().parent.parent.parent)
@staticmethod
def get_version():
if (version_number := Constants.HV_CLIENT_VERSION_NUMBER) is None:
raise UnknownClientVersionError('The client version could not be determined.')
return ClientVersionController.get_or_new(version_number)
@staticmethod
def can_be_updated():
try:
version = ClientController.get_version()
except UnknownClientVersionError:
return False
return not ClientVersionController.is_latest(version)
@staticmethod
def sync(client_observer: ClientObserver = None, connection_observer: ConnectionObserver = None):
from core.models.manage.session_management import init_session, close_session
init_session()
print("I sync'ed")
# Use Cached Method:
changed_tables = coordinate_cache_sync(ClientObserver, ConnectionObserver)
# SPOOFING
# changed_tables = ['version', 'applications', 'application_versions', 'client_version', 'operators', 'locations', 'subscriptions']
print(f"changed_tables: {changed_tables}")
# this should be same or any errors:
if isinstance(changed_tables, dict):
# check result is "same"?
# or an errro
if client_observer is not None:
client_observer.notify('synchronized')
# now it's likely to have results:
if isinstance(changed_tables, list):
quantity_of_changes = len(changed_tables)
print(f"quantity_of_changes is {quantity_of_changes}")
# sanity check:
if quantity_of_changes >= 0:
from core.controllers.ConnectionController import ConnectionController
ConnectionController.with_preferred_connection(task=ClientController.__sync, changed_tables=changed_tables, client_observer=client_observer, connection_observer=connection_observer)
else:
if client_observer is not None:
client_observer.notify('synchronized')
@staticmethod
def update(client_observer: ClientObserver = None, connection_observer: ConnectionObserver = None):
from core.controllers.ConnectionController import ConnectionController
ConnectionController.with_preferred_connection(task=ClientController.__update, client_observer=client_observer, connection_observer=connection_observer)
@staticmethod
def __get_path():
if (path := Constants.HV_CLIENT_PATH) is None:
raise UnknownClientPathError('The client path could not be determined.')
return path
# def cached_sync(client_observer: Optional[ClientObserver] = None, proxies: Optional[dict] = None):
@staticmethod
def __sync(changed_tables: list, client_observer: Optional[ClientObserver] = None, proxies: Optional[dict] = None):
# SPOOFING
# changed_tables = ['version', 'applications', 'application_versions', 'client_version', 'operators', 'locations', 'subscriptions']
if client_observer is not None:
client_observer.notify('synchronizing')
if "applications" in changed_tables:
print("sync applications")
# noinspection PyProtectedMember
ApplicationController._sync(proxies=proxies)
if "application_versions" in changed_tables:
print("sync application_versions")
# noinspection PyProtectedMember
ApplicationVersionController._sync(proxies=proxies)
if "client_version" in changed_tables:
print("sync client_version")
# noinspection PyProtectedMember
ClientVersionController._sync(proxies=proxies)
if "operators" in changed_tables:
print("sync operators")
# noinspection PyProtectedMember
OperatorController._sync(proxies=proxies)
if "locations" in changed_tables:
print("sync locations")
# noinspection PyProtectedMember
LocationController._sync(proxies=proxies)
if "subscriptions" in changed_tables:
print("sync subscriptions")
# noinspection PyProtectedMember
SubscriptionPlanController._sync(proxies=proxies)
ConfigurationController.update_last_synced_at()
if client_observer is not None:
client_observer.notify('synchronized')
@staticmethod
def __update(client_observer: Optional[ClientObserver] = None, proxies: Optional[dict] = None):
if ClientController.can_be_updated():
if client_observer is not None:
client_observer.notify('updating')
client_path = ClientController.__get_path()
update_environment = os.environ.copy()
if proxies is not None:
update_environment | dict(http_proxy=proxies['http'], https_proxy=proxies['https'])
if shutil.which('hv-updater') is None:
raise CommandNotFoundError('hv-updater')
process = subprocess.Popen(('hv-updater', '--overwrite', '--remove-old', client_path), env=update_environment, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True)
highest_reported_progress = 0
for line in iter(process.stdout.readline, ''):
match = re.search(r'(\d+\.\d+)%', line)
if match and (progress := float(match.group(1))) > highest_reported_progress:
highest_reported_progress = progress
if client_observer is not None:
client_observer.notify('update_progressing', None, dict(
progress=progress
))
if client_observer is not None:
client_observer.notify('updated')