Implement support for incremental client updates
This commit is contained in:
parent
d33a73bb96
commit
b744ed0a2d
4 changed files with 73 additions and 4 deletions
|
@ -8,6 +8,9 @@ class Constants:
|
||||||
|
|
||||||
SP_API_BASE_URL: Final[str] = 'https://api.simplifiedprivacy.is/api/v1'
|
SP_API_BASE_URL: Final[str] = 'https://api.simplifiedprivacy.is/api/v1'
|
||||||
|
|
||||||
|
HV_CLIENT_PATH: Final[str] = os.environ.get('HV_CLIENT_PATH')
|
||||||
|
HV_CLIENT_VERSION_NUMBER: Final[str] = os.environ.get('HV_CLIENT_VERSION_NUMBER')
|
||||||
|
|
||||||
HOME: Final[str] = os.path.expanduser('~')
|
HOME: Final[str] = os.path.expanduser('~')
|
||||||
|
|
||||||
SYSTEM_CONFIG_PATH: Final[str] = '/etc'
|
SYSTEM_CONFIG_PATH: Final[str] = '/etc'
|
||||||
|
|
|
@ -6,6 +6,10 @@ class CommandNotFoundError(OSError):
|
||||||
super().__init__(f"Command '{subject}' could not be found.")
|
super().__init__(f"Command '{subject}' could not be found.")
|
||||||
|
|
||||||
|
|
||||||
|
class UnknownClientPathError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class UnknownClientVersionError(Exception):
|
class UnknownClientVersionError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from core.Errors import UnknownClientVersionError
|
from core.Constants import Constants
|
||||||
|
from core.Errors import UnknownClientPathError, UnknownClientVersionError, CommandNotFoundError
|
||||||
from core.controllers.ApplicationController import ApplicationController
|
from core.controllers.ApplicationController import ApplicationController
|
||||||
from core.controllers.ApplicationVersionController import ApplicationVersionController
|
from core.controllers.ApplicationVersionController import ApplicationVersionController
|
||||||
from core.controllers.ClientVersionController import ClientVersionController
|
from core.controllers.ClientVersionController import ClientVersionController
|
||||||
|
@ -10,6 +11,9 @@ from core.observers.ConnectionObserver import ConnectionObserver
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
import os
|
import os
|
||||||
import pathlib
|
import pathlib
|
||||||
|
import re
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
|
||||||
class ClientController:
|
class ClientController:
|
||||||
|
@ -21,9 +25,7 @@ class ClientController:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_version():
|
def get_version():
|
||||||
|
|
||||||
version_number = os.environ.get('HV_VERSION_NUMBER')
|
if (version_number := Constants.HV_CLIENT_VERSION_NUMBER) is None:
|
||||||
|
|
||||||
if version_number is None:
|
|
||||||
raise UnknownClientVersionError('The client version could not be determined.')
|
raise UnknownClientVersionError('The client version could not be determined.')
|
||||||
|
|
||||||
return ClientVersionController.get_or_new(version_number)
|
return ClientVersionController.get_or_new(version_number)
|
||||||
|
@ -44,6 +46,20 @@ class ClientController:
|
||||||
from core.controllers.ConnectionController import ConnectionController
|
from core.controllers.ConnectionController import ConnectionController
|
||||||
ConnectionController.with_preferred_connection(task=ClientController.__sync, client_observer=client_observer, connection_observer=connection_observer)
|
ConnectionController.with_preferred_connection(task=ClientController.__sync, client_observer=client_observer, connection_observer=connection_observer)
|
||||||
|
|
||||||
|
@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
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def __sync(client_observer: Optional[ClientObserver] = None, proxies: Optional[dict] = None):
|
def __sync(client_observer: Optional[ClientObserver] = None, proxies: Optional[dict] = None):
|
||||||
|
|
||||||
|
@ -62,3 +78,44 @@ class ClientController:
|
||||||
SubscriptionPlanController._sync(proxies=proxies)
|
SubscriptionPlanController._sync(proxies=proxies)
|
||||||
|
|
||||||
ConfigurationController.update_last_synced_at()
|
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')
|
||||||
|
|
|
@ -4,4 +4,9 @@ from core.observers.BaseObserver import BaseObserver
|
||||||
class ClientObserver(BaseObserver):
|
class ClientObserver(BaseObserver):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
self.on_synchronizing = []
|
self.on_synchronizing = []
|
||||||
|
self.on_synchronized = []
|
||||||
|
self.on_updating = []
|
||||||
|
self.on_update_progressing = []
|
||||||
|
self.on_updated = []
|
||||||
|
|
Loading…
Reference in a new issue