Update file management-related logic

This commit is contained in:
codeking 2026-02-11 09:48:08 +01:00
parent a0eba19b91
commit 0ab1ac4168
10 changed files with 28 additions and 40 deletions

19
core/Helpers.py Normal file
View file

@ -0,0 +1,19 @@
import os
def write_atomically(file_path, contents):
staging_file_path = f'{file_path}~'
try:
with open(staging_file_path, 'w') as config_staging_file:
config_staging_file.write(contents)
config_staging_file.flush()
os.fsync(config_staging_file.fileno())
os.replace(staging_file_path, file_path)
finally:
if os.path.exists(staging_file_path):
os.remove(staging_file_path)

View file

@ -87,9 +87,7 @@ class ApplicationController:
Path(initialization_file_path).touch(exist_ok=True, mode=0o600 | stat.S_IEXEC) Path(initialization_file_path).touch(exist_ok=True, mode=0o600 | stat.S_IEXEC)
with open(initialization_file_path, 'w') as initialization_file: with open(initialization_file_path, 'w') as initialization_file:
initialization_file.write(initialization_file_contents) initialization_file.write(initialization_file_contents)
initialization_file.close()
if asynchronous: if asynchronous:

View file

@ -99,14 +99,10 @@ class ApplicationVersionController:
raise FileIntegrityError('Application version file integrity could not be verified.') raise FileIntegrityError('Application version file integrity could not be verified.')
with tarfile.open(fileobj=response_buffer, mode = 'r:gz') as tar_file: with tarfile.open(fileobj=response_buffer, mode = 'r:gz') as tar_file:
tar_file.extractall(application_version.get_installation_path()) tar_file.extractall(application_version.get_installation_path())
tar_file.close()
with open(f'{application_version.get_installation_path()}/.sha3-512', 'w') as hash_file: with open(f'{application_version.get_installation_path()}/.sha3-512', 'w') as hash_file:
hash_file.write(f'{file_hash}\n') hash_file.write(f'{file_hash}\n')
hash_file.close()
else: else:
raise ConnectionError('The application version could not be downloaded.') raise ConnectionError('The application version could not be downloaded.')

View file

@ -340,9 +340,7 @@ class ConnectionController:
Path(wireproxy_configuration_file_path).touch(exist_ok=True, mode=0o600) Path(wireproxy_configuration_file_path).touch(exist_ok=True, mode=0o600)
with open(wireproxy_configuration_file_path, 'w') as wireproxy_configuration_file: with open(wireproxy_configuration_file_path, 'w') as wireproxy_configuration_file:
wireproxy_configuration_file.write(f'WGConfig = {profile.get_wireguard_configuration_path()}\n\n[Socks5]\nBindAddress = 127.0.0.1:{str(port_number)}\n') wireproxy_configuration_file.write(f'WGConfig = {profile.get_wireguard_configuration_path()}\n\n[Socks5]\nBindAddress = 127.0.0.1:{str(port_number)}\n')
wireproxy_configuration_file.close()
return subprocess.Popen((f'{Constants.HV_RUNTIME_DATA_HOME}/wireproxy/wireproxy', '-c', wireproxy_configuration_file_path), stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT) return subprocess.Popen((f'{Constants.HV_RUNTIME_DATA_HOME}/wireproxy/wireproxy', '-c', wireproxy_configuration_file_path), stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
@ -379,9 +377,7 @@ class ConnectionController:
proxychains_configuration_file_contents = proxychains_template_file.read().format(proxy_list=proxychains_proxy_list) proxychains_configuration_file_contents = proxychains_template_file.read().format(proxy_list=proxychains_proxy_list)
with open(proxychains_configuration_file_path, 'w') as proxychains_configuration_file: with open(proxychains_configuration_file_path, 'w') as proxychains_configuration_file:
proxychains_configuration_file.write(proxychains_configuration_file_contents) proxychains_configuration_file.write(proxychains_configuration_file_contents)
proxychains_configuration_file.close()
return subprocess.Popen(('proxychains4', '-f', proxychains_configuration_file_path, 'microsocks', '-p', str(proxy_port_number)), stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT) return subprocess.Popen(('proxychains4', '-f', proxychains_configuration_file_path, 'microsocks', '-p', str(proxy_port_number)), stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)

View file

@ -1,11 +1,11 @@
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from core.Constants import Constants from core.Constants import Constants
from core.Helpers import write_atomically
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, asdict 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 pathlib import Path from pathlib import Path
from typing import Optional, Self from typing import Optional, Self
import json import json
@ -59,11 +59,7 @@ class BaseProfile(ABC):
os.makedirs(self.get_data_path(), exist_ok=True) os.makedirs(self.get_data_path(), exist_ok=True)
config_file_path = f'{self.get_config_path()}/config.json' config_file_path = f'{self.get_config_path()}/config.json'
write_atomically(config_file_path, config_file_contents)
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(self.get_data_path(), ignore_errors=True) shutil.rmtree(self.get_data_path(), ignore_errors=True)
@ -160,7 +156,7 @@ class BaseProfile(ABC):
try: try:
profile = json.loads(config_file_contents) profile = json.loads(config_file_contents)
except JSONDecodeError: except ValueError:
return None return None
profile['id'] = id profile['id'] = id

View file

@ -1,8 +1,8 @@
from core.Constants import Constants from core.Constants import Constants
from core.Helpers import write_atomically
from dataclasses import dataclass, field from dataclasses import dataclass, field
from dataclasses_json import dataclass_json, config from dataclasses_json import dataclass_json, config
from datetime import datetime from datetime import datetime
from json import JSONDecodeError
from marshmallow import fields from marshmallow import fields
from typing import Optional, Self from typing import Optional, Self
from zoneinfo import ZoneInfo from zoneinfo import ZoneInfo
@ -53,11 +53,7 @@ class Configuration:
os.makedirs(Constants.HV_CONFIG_HOME, exist_ok=True) os.makedirs(Constants.HV_CONFIG_HOME, exist_ok=True)
config_file_path = f'{Constants.HV_CONFIG_HOME}/config.json' config_file_path = f'{Constants.HV_CONFIG_HOME}/config.json'
write_atomically(config_file_path, config_file_contents)
with open(config_file_path, 'w') as config_file:
config_file.write(config_file_contents)
config_file.close()
@staticmethod @staticmethod
def get(): def get():
@ -69,7 +65,7 @@ class Configuration:
try: try:
configuration = json.loads(config_file_contents) configuration = json.loads(config_file_contents)
except JSONDecodeError: except ValueError:
sys.exit(1) sys.exit(1)
# noinspection PyUnresolvedReferences # noinspection PyUnresolvedReferences

View file

@ -5,7 +5,6 @@ from core.models.session.ApplicationVersion import ApplicationVersion
from core.models.session.ProxyConfiguration import ProxyConfiguration from core.models.session.ProxyConfiguration import ProxyConfiguration
from core.models.session.SessionConnection import SessionConnection from core.models.session.SessionConnection import SessionConnection
from dataclasses import dataclass from dataclasses import dataclass
from json import JSONDecodeError
from pathlib import Path from pathlib import Path
from typing import Optional from typing import Optional
import json import json
@ -46,18 +45,14 @@ class SessionProfile(BaseProfile):
proxy_configuration_file_path = self.get_proxy_configuration_path() proxy_configuration_file_path = self.get_proxy_configuration_path()
with open(proxy_configuration_file_path, 'w') as proxy_configuration_file: with open(proxy_configuration_file_path, 'w') as proxy_configuration_file:
proxy_configuration_file.write(proxy_configuration_file_contents) proxy_configuration_file.write(proxy_configuration_file_contents)
proxy_configuration_file.close()
def attach_wireguard_configuration(self, wireguard_configuration): def attach_wireguard_configuration(self, wireguard_configuration):
wireguard_configuration_file_path = self.get_wireguard_configuration_path() wireguard_configuration_file_path = self.get_wireguard_configuration_path()
with open(wireguard_configuration_file_path, 'w') as wireguard_configuration_file: with open(wireguard_configuration_file_path, 'w') as wireguard_configuration_file:
wireguard_configuration_file.write(wireguard_configuration) wireguard_configuration_file.write(wireguard_configuration)
wireguard_configuration_file.close()
def get_proxy_configuration_path(self): def get_proxy_configuration_path(self):
return f'{self.get_config_path()}/proxy.json' return f'{self.get_config_path()}/proxy.json'
@ -74,7 +69,7 @@ class SessionProfile(BaseProfile):
try: try:
proxy_configuration = json.loads(config_file_contents) proxy_configuration = json.loads(config_file_contents)
except JSONDecodeError: except ValueError:
return None return None
proxy_configuration = ProxyConfiguration.from_dict(proxy_configuration) proxy_configuration = ProxyConfiguration.from_dict(proxy_configuration)

View file

@ -2,7 +2,6 @@ from core.Constants import Constants
from core.models.session.NetworkPortNumbers import NetworkPortNumbers from core.models.session.NetworkPortNumbers import NetworkPortNumbers
from dataclasses import dataclass, field from dataclasses import dataclass, field
from dataclasses_json import config, Exclude, dataclass_json from dataclasses_json import config, Exclude, dataclass_json
from json import JSONDecodeError
from pathlib import Path from pathlib import Path
from typing import Self from typing import Self
import json import json
@ -33,9 +32,7 @@ class SessionState:
Path(session_state_file_path).touch(exist_ok=True, mode=0o600) Path(session_state_file_path).touch(exist_ok=True, mode=0o600)
with open(session_state_file_path, 'w') as session_state_file: with open(session_state_file_path, 'w') as session_state_file:
session_state_file.write(session_state_file_contents) session_state_file.write(session_state_file_contents)
session_state_file.close()
@staticmethod @staticmethod
def find_by_id(id: int): def find_by_id(id: int):
@ -55,7 +52,7 @@ class SessionState:
# noinspection PyUnresolvedReferences # noinspection PyUnresolvedReferences
return SessionState.from_dict(session_state) return SessionState.from_dict(session_state)
except (JSONDecodeError, AttributeError): except (ValueError, AttributeError):
shutil.rmtree(Path(state_path), ignore_errors=True) shutil.rmtree(Path(state_path), ignore_errors=True)
return None return None

View file

@ -31,9 +31,7 @@ class SystemProfile(BaseProfile):
wireguard_configuration_file_backup_path = f'{self.get_config_path()}/wg.conf.bak' wireguard_configuration_file_backup_path = f'{self.get_config_path()}/wg.conf.bak'
with open(wireguard_configuration_file_backup_path, 'w') as wireguard_configuration_file: with open(wireguard_configuration_file_backup_path, 'w') as wireguard_configuration_file:
wireguard_configuration_file.write(wireguard_configuration) wireguard_configuration_file.write(wireguard_configuration)
wireguard_configuration_file.close()
wireguard_configuration_is_attached = False wireguard_configuration_is_attached = False
failed_attempt_count = 0 failed_attempt_count = 0

View file

@ -1,7 +1,6 @@
from core.Constants import Constants from core.Constants import Constants
from dataclasses import dataclass from dataclasses import dataclass
from dataclasses_json import dataclass_json from dataclasses_json import dataclass_json
from json import JSONDecodeError
from pathlib import Path from pathlib import Path
from typing import Self from typing import Self
import json import json
@ -22,9 +21,7 @@ class SystemState:
Path(system_state_file_path).touch(exist_ok=True, mode=0o600) Path(system_state_file_path).touch(exist_ok=True, mode=0o600)
with open(system_state_file_path, 'w') as system_state_file: with open(system_state_file_path, 'w') as system_state_file:
system_state_file.write(system_state_file_contents) system_state_file.write(system_state_file_contents)
system_state_file.close()
@staticmethod @staticmethod
def get(): def get():
@ -37,7 +34,7 @@ class SystemState:
# noinspection PyUnresolvedReferences # noinspection PyUnresolvedReferences
return SystemState.from_dict(system_state_dict) return SystemState.from_dict(system_state_dict)
except (FileNotFoundError, JSONDecodeError, KeyError): except (FileNotFoundError, ValueError, KeyError):
return None return None
@staticmethod @staticmethod