Add support for embedded time zone data

This commit is contained in:
codeking 2025-03-14 02:43:13 +01:00
parent fd6948a6a3
commit d33a73bb96
9 changed files with 75 additions and 15 deletions

View file

@ -14,6 +14,10 @@ class UnknownConnectionTypeError(Exception):
pass pass
class UnknownTimeZoneError(Exception):
pass
class ConnectionTerminationError(Exception): class ConnectionTerminationError(Exception):
pass pass

View file

@ -39,9 +39,10 @@ class ApplicationController:
shutil.copytree(f'{version.get_installation_path()}/resources/initial-state', persistent_state_path) shutil.copytree(f'{version.get_installation_path()}/resources/initial-state', persistent_state_path)
display = ApplicationController.__find_unused_display() display = ApplicationController.__find_unused_display()
time_zone = profile.determine_timezone()
base_initialization_file_template = open(f'/{Constants.HV_RUNTIME_DATA_HOME}/.init.ptpl', 'r').read() base_initialization_file_template = open(f'/{Constants.HV_RUNTIME_DATA_HOME}/.init.ptpl', 'r').read()
base_initialization_file_contents = base_initialization_file_template.format(display=display, time_zone=profile.location.time_zone, hv_data_home=Constants.HV_DATA_HOME) base_initialization_file_contents = base_initialization_file_template.format(display=display, time_zone=time_zone, hv_data_home=Constants.HV_DATA_HOME)
application_initialization_file_template = open(f'/{version.get_installation_path()}/.init.ptpl', 'r').read() application_initialization_file_template = open(f'/{version.get_installation_path()}/.init.ptpl', 'r').read()
application_initialization_file_contents = application_initialization_file_template.format(application_version_home=version.get_installation_path(), port_number=port_number or -1, home=Constants.HOME, profile_data_path=profile.get_data_path(), config_home=Constants.CONFIG_HOME, application_version_number=version.version_number) application_initialization_file_contents = application_initialization_file_template.format(application_version_home=version.get_installation_path(), port_number=port_number or -1, home=Constants.HOME, profile_data_path=profile.get_data_path(), config_home=Constants.CONFIG_HOME, application_version_number=version.version_number)

View file

@ -83,11 +83,14 @@ class ApplicationVersionController:
response_buffer.write(data) response_buffer.write(data)
progress = (bytes_written / response_size) * 100 if response_size > 0 else 0 progress = (bytes_written / response_size) * 100 if response_size > 0 else 0
if application_version_observer is not None:
application_version_observer.notify('download_progressing', application_version, dict( application_version_observer.notify('download_progressing', application_version, dict(
progress=progress progress=progress
)) ))
application_version_observer.notify('downloaded', application_version) application_version_observer.notify('downloaded', application_version)
response_buffer.seek(0) response_buffer.seek(0)
file_hash = ApplicationVersionController.__calculate_file_hash(response_buffer) file_hash = ApplicationVersionController.__calculate_file_hash(response_buffer)

View file

@ -31,6 +31,9 @@ class BaseProfile:
def has_subscription(self): def has_subscription(self):
return self.subscription is not None return self.subscription is not None
def has_location(self):
return self.location is not None
def is_session_profile(self): def is_session_profile(self):
return type(self).__name__ == 'SessionProfile' return type(self).__name__ == 'SessionProfile'

View file

@ -1,7 +1,6 @@
from core.models.Model import Model from core.models.Model import Model
from dataclasses import dataclass, field from dataclasses import dataclass, field
from dataclasses_json import config, Exclude from dataclasses_json import config, Exclude
from pytz import country_timezones
from typing import Optional from typing import Optional
_table_name: str = 'locations' _table_name: str = 'locations'
@ -33,17 +32,13 @@ class Location(Model):
default=None, default=None,
metadata=config(exclude=Exclude.ALWAYS) metadata=config(exclude=Exclude.ALWAYS)
) )
time_zone: str = None time_zone: Optional[str] = None
available: Optional[bool] = field( available: Optional[bool] = field(
default=False, default=False,
metadata=config(exclude=Exclude.ALWAYS) metadata=config(exclude=Exclude.ALWAYS)
) )
def __post_init__(self): def __post_init__(self):
if self.time_zone is None:
self.time_zone = country_timezones[self.country_code][0]
self.available = self.exists(self.country_code, self.code) self.available = self.exists(self.country_code, self.code)
def is_available(self): def is_available(self):

View file

@ -1,5 +1,7 @@
from dataclasses import dataclass from dataclasses import dataclass, field
from dataclasses_json import dataclass_json from dataclasses_json import dataclass_json, config
from typing import Optional
import dataclasses_json
@dataclass_json @dataclass_json
@ -9,3 +11,10 @@ class ProxyConfiguration:
port_number: int port_number: int
username: str username: str
password: str password: str
time_zone: Optional[str] = field(
default=None,
metadata=config(
undefined=dataclasses_json.Undefined.EXCLUDE,
exclude=lambda value: value is None
)
)

View file

@ -1,4 +1,5 @@
from core.Constants import Constants from core.Constants import Constants
from core.Errors import UnknownTimeZoneError
from core.models.BaseProfile import BaseProfile from core.models.BaseProfile import BaseProfile
from core.models.session.ApplicationVersion import ApplicationVersion from core.models.session.ApplicationVersion import ApplicationVersion
from core.models.session.ProxyConfiguration import ProxyConfiguration from core.models.session.ProxyConfiguration import ProxyConfiguration
@ -8,6 +9,7 @@ from json import JSONDecodeError
from typing import Optional from typing import Optional
import json import json
import os import os
import re
import shutil import shutil
@ -17,6 +19,9 @@ class SessionProfile(BaseProfile):
application_version: Optional[ApplicationVersion] application_version: Optional[ApplicationVersion]
connection: Optional[SessionConnection] connection: Optional[SessionConnection]
def has_connection(self):
return self.connection is not None
def save(self): def save(self):
if 'application_version' in self._get_dirty_keys(): if 'application_version' in self._get_dirty_keys():
@ -76,3 +81,44 @@ class SessionProfile(BaseProfile):
def has_wireguard_configuration(self): def has_wireguard_configuration(self):
return os.path.isfile(f'{self.get_config_path()}/wg.conf') return os.path.isfile(f'{self.get_config_path()}/wg.conf')
def determine_timezone(self):
time_zone = None
if self.has_connection():
if self.connection.needs_proxy_configuration():
if self.has_proxy_configuration():
time_zone = self.get_proxy_configuration().time_zone
elif self.connection.needs_wireguard_configuration():
if self.has_wireguard_configuration():
time_zone = self.__get_wireguard_configuration_metadata('TZ')
if time_zone is None and self.has_location():
time_zone = self.location.time_zone
if time_zone is None:
raise UnknownTimeZoneError('The preferred time zone could not be determined.')
return time_zone
def __get_wireguard_configuration(self):
try:
with open(self.get_wireguard_configuration_path(), 'r') as file:
return file.readlines()
except FileNotFoundError:
return None
def __get_wireguard_configuration_metadata(self, key):
for line in self.__get_wireguard_configuration():
match = re.match(r'^# {} = (.*)$'.format(re.escape(key)), line)
if match:
return re.sub(r'[^a-zA-Z0-9+\- /]', '', match.group(1).strip())

View file

@ -129,7 +129,7 @@ class WebServiceApiService:
if response.status_code == requests.codes.ok: if response.status_code == requests.codes.ok:
proxy_configuration = response.json()['data'] proxy_configuration = response.json()['data']
return ProxyConfiguration(proxy_configuration['ip_address'], proxy_configuration['port'], proxy_configuration['username'], proxy_configuration['password']) return ProxyConfiguration(proxy_configuration['ip_address'], proxy_configuration['port'], proxy_configuration['username'], proxy_configuration['password'], proxy_configuration['location']['time_zone']['code'])
else: else:
return None return None

View file

@ -18,7 +18,6 @@ dependencies = [
"psutil ~= 5.9.8", "psutil ~= 5.9.8",
"pysocks ~= 1.7.1", "pysocks ~= 1.7.1",
"python-dateutil ~= 2.9.0.post0", "python-dateutil ~= 2.9.0.post0",
"pytz ~= 2024.1",
"requests ~= 2.32.0", "requests ~= 2.32.0",
] ]