Add support for conditional persistent state preservation

This commit is contained in:
codeking 2025-03-12 02:11:44 +01:00
parent 43866a0807
commit 7f9c6ab1a9
4 changed files with 44 additions and 35 deletions

View file

@ -30,7 +30,7 @@ class ProfileController:
@staticmethod @staticmethod
def create(profile: Union[SessionProfile, SystemProfile], profile_observer: ProfileObserver = None): def create(profile: Union[SessionProfile, SystemProfile], profile_observer: ProfileObserver = None):
Profile.save(profile) profile.save()
if profile_observer is not None: if profile_observer is not None:
profile_observer.notify('created', profile) profile_observer.notify('created', profile)
@ -38,7 +38,7 @@ class ProfileController:
@staticmethod @staticmethod
def update(profile: Union[SessionProfile, SystemProfile], profile_observer: ProfileObserver = None): def update(profile: Union[SessionProfile, SystemProfile], profile_observer: ProfileObserver = None):
Profile.save(profile) profile.save()
if profile_observer is not None: if profile_observer is not None:
profile_observer.notify('updated', profile) profile_observer.notify('updated', profile)
@ -136,7 +136,7 @@ class ProfileController:
def attach_subscription(profile: Union[SessionProfile, SystemProfile], subscription: Subscription): def attach_subscription(profile: Union[SessionProfile, SystemProfile], subscription: Subscription):
profile.subscription = subscription profile.subscription = subscription
profile.save(profile) profile.save()
@staticmethod @staticmethod
def activate_subscription(profile: Union[SessionProfile, SystemProfile], connection_observer: Optional[ConnectionObserver] = None): def activate_subscription(profile: Union[SessionProfile, SystemProfile], connection_observer: Optional[ConnectionObserver] = None):
@ -150,7 +150,7 @@ class ProfileController:
if subscription is not None: if subscription is not None:
profile.subscription = subscription profile.subscription = subscription
profile.save(profile) profile.save()
else: else:
raise InvalidSubscriptionError() raise InvalidSubscriptionError()

View file

@ -2,10 +2,10 @@ from core.Constants import Constants
from core.models.Location import Location from core.models.Location import Location
from core.models.Subscription import Subscription from core.models.Subscription import Subscription
from core.models.session.ApplicationVersion import ApplicationVersion from core.models.session.ApplicationVersion import ApplicationVersion
from dataclasses import dataclass, field from dataclasses import dataclass, field, asdict
from dataclasses_json import config, Exclude, dataclass_json from dataclasses_json import config, Exclude, dataclass_json
from json import JSONDecodeError from json import JSONDecodeError
from typing import Optional from typing import Optional, Self
import json import json
import os import os
import re import re
@ -37,17 +37,36 @@ class BaseProfile:
def is_system_profile(self): def is_system_profile(self):
return type(self).__name__ == 'SystemProfile' return type(self).__name__ == 'SystemProfile'
def save(self: Self):
config_file_contents = f'{self.to_json(indent=4)}\n'
os.makedirs(self.get_config_path(), exist_ok=True)
os.makedirs(self.get_data_path(), exist_ok=True)
config_file_path = f'{self.get_config_path()}/config.json'
with open(config_file_path, 'w') as config_file:
config_file.write(config_file_contents)
config_file.close()
def delete_data(self): def delete_data(self):
shutil.rmtree(BaseProfile.__get_data_path(self.id), ignore_errors=True) shutil.rmtree(self.get_data_path(), ignore_errors=True)
def delete(self): def delete(self):
self._delete() shutil.rmtree(self.get_config_path(), ignore_errors=True)
def _delete(self):
shutil.rmtree(BaseProfile.__get_config_path(self.id), ignore_errors=True)
self.delete_data() self.delete_data()
def _get_dirty_keys(self: Self):
reference = BaseProfile.find_by_id(self.id)
if type(reference) != type(self):
return list(self.__dataclass_fields__.keys())
return list([key for key, value in asdict(self).items() if value != asdict(reference).get(key)])
@staticmethod @staticmethod
def find_by_id(id: int): def find_by_id(id: int):
@ -119,28 +138,6 @@ class BaseProfile:
return dict(sorted(profiles.items())) return dict(sorted(profiles.items()))
@staticmethod
def save(profile):
if profile.is_session_profile() and profile.application_version is not None:
persistent_state_path = f'{BaseProfile.__get_data_path(profile.id)}/persistent-state'
if os.path.isdir(persistent_state_path):
shutil.rmtree(persistent_state_path, ignore_errors=True)
config_file_contents = f'{profile.to_json(indent=4)}\n'
os.makedirs(BaseProfile.__get_config_path(profile.id), exist_ok=True)
os.makedirs(BaseProfile.__get_data_path(profile.id), exist_ok=True)
config_file_path = f'{BaseProfile.__get_config_path(profile.id)}/config.json'
with open(config_file_path, 'w') as config_file:
config_file.write(config_file_contents)
config_file.close()
@staticmethod @staticmethod
def __get_config_path(id: int): def __get_config_path(id: int):
return f'{Constants.HV_PROFILE_CONFIG_HOME}/{str(id)}' return f'{Constants.HV_PROFILE_CONFIG_HOME}/{str(id)}'

View file

@ -8,6 +8,7 @@ from json import JSONDecodeError
from typing import Optional from typing import Optional
import json import json
import os import os
import shutil
@dataclass @dataclass
@ -16,6 +17,17 @@ class SessionProfile(BaseProfile):
application_version: Optional[ApplicationVersion] application_version: Optional[ApplicationVersion]
connection: Optional[SessionConnection] connection: Optional[SessionConnection]
def save(self):
if 'application_version' in self._get_dirty_keys():
persistent_state_path = f'{self.get_data_path()}/persistent-state'
if os.path.isdir(persistent_state_path):
shutil.rmtree(persistent_state_path, ignore_errors=True)
super().save()
def attach_proxy_configuration(self, proxy_configuration): def attach_proxy_configuration(self, proxy_configuration):
proxy_configuration_file_contents = f'{proxy_configuration.to_json(indent=4)}\n' proxy_configuration_file_contents = f'{proxy_configuration.to_json(indent=4)}\n'

View file

@ -61,7 +61,7 @@ class SystemProfile(BaseProfile):
if not completed_successfully: if not completed_successfully:
raise ProfileDeletionError('The profile could not be deleted.') raise ProfileDeletionError('The profile could not be deleted.')
self._delete() super().delete()
@staticmethod @staticmethod
def __get_system_config_path(id: int): def __get_system_config_path(id: int):