Linter bug fixes. Mostly undeclared, unused, or missing imports. One or two outright typos. There's still issues with undeclared types that need to be fixed after api connection refactor is fully implemented.

This commit is contained in:
SimplifiedPrivacy 2026-08-05 12:03:11 -04:00
parent a5f57f4f5e
commit 8da4978498
34 changed files with 228 additions and 150 deletions

View file

@ -59,86 +59,86 @@ class ClientController:
return not ClientVersionController.is_latest(version) return not ClientVersionController.is_latest(version)
@staticmethod # @staticmethod
def legacy_sync(client_observer: ClientObserver = None, connection_observer: ConnectionObserver = None): # def legacy_sync(client_observer: ClientObserver = None, connection_observer: ConnectionObserver = None):
if client_observer is not None: # if client_observer is not None:
client_observer.notify('synchronizing', "Fetching list of new data ..") # client_observer.notify('synchronizing', "Fetching list of new data ..")
result = coordinate_cache_sync(client_observer, connection_observer) # result = coordinate_cache_sync(client_observer, connection_observer)
# Outright Error: # # Outright Error:
if not result["success"]: # if not result["success"]:
error_msg = result["error"] # error_msg = result["error"]
if client_observer is not None: # if client_observer is not None:
client_observer.notify('synchronizing', f'Error! {error_msg}') # client_observer.notify('synchronizing', f'Error! {error_msg}')
return # return
# Same: # # Same:
changed_tables = result["changed_tables"] # changed_tables = result["changed_tables"]
if not changed_tables: # if not changed_tables:
if client_observer is not None: # if client_observer is not None:
client_observer.notify('synchronized') # client_observer.notify('synchronized')
return # return
# We only make it past this point if there's New Data # # We only make it past this point if there's New Data
# flag for after the save, # # flag for after the save,
data_was_saved = False # data_was_saved = False
# Fetch and update the real data (no longer metadata)... # # Fetch and update the real data (no longer metadata)...
# =================== ORM BASED MODELS ================== # # =================== ORM BASED MODELS ==================
""" # """
Note: for the new ORM based models, # Note: for the new ORM based models,
it does the Tor/system check in the API call itself. # it does the Tor/system check in the API call itself.
""" # """
if "locations" in changed_tables: # if "locations" in changed_tables:
logger.info("Sync of Locations") # logger.info("Sync of Locations")
if client_observer is not None: # if client_observer is not None:
client_observer.notify('synchronizing', 'Fetching Locations List..') # client_observer.notify('synchronizing', 'Fetching Locations List..')
final_result = sync_one_orm_model(Location, "locations") # final_result = sync_one_orm_model(Location, "locations")
evaluate_errors(final_result) # evaluate_errors(final_result)
if "operators" in changed_tables: # if "operators" in changed_tables:
logger.info("Sync of Operators") # logger.info("Sync of Operators")
if client_observer is not None: # if client_observer is not None:
client_observer.notify('synchronizing', 'Fetching Operators List..') # client_observer.notify('synchronizing', 'Fetching Operators List..')
final_result_two = sync_one_orm_model(Operator, "operators") # final_result_two = sync_one_orm_model(Operator, "operators")
evaluate_errors(final_result_two) # evaluate_errors(final_result_two)
# =================== MANUAL-SQL BASED MODELS ================== # # =================== MANUAL-SQL BASED MODELS ==================
try: # try:
from core.controllers.ConnectionController import ConnectionController # 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) # ConnectionController.with_preferred_connection(task=ClientController.__sync, changed_tables=changed_tables, client_observer=client_observer, connection_observer=connection_observer)
# We set the flag to true, # # We set the flag to true,
# the reason we use a flag, and don't just save it right here, # # the reason we use a flag, and don't just save it right here,
# is because we want to isolate the success (or failure) of the real data, # # is because we want to isolate the success (or failure) of the real data,
# from the potential failure of the ORM session metadata. # # from the potential failure of the ORM session metadata.
data_was_saved = True # data_was_saved = True
except: # except:
# sync failed here, # # sync failed here,
if client_observer is not None: # if client_observer is not None:
client_observer.notify('synchronizing', 'Fetch Failed, but you can use old data.') # client_observer.notify('synchronizing', 'Fetch Failed, but you can use old data.')
finally: # finally:
if data_was_saved: # if data_was_saved:
filtered_metadata = result["filtered_metadata"] # from the top of the function # filtered_metadata = result["filtered_metadata"] # from the top of the function
save_successful = save_metadata(filtered_metadata) # the "save_data" function is inside sync_service # save_successful = save_metadata(filtered_metadata) # the "save_data" function is inside sync_service
if client_observer is None: # if client_observer is None:
logger.error("Error: No client_observer to update the UI, the final part of the sync function skipped") # logger.error("Error: No client_observer to update the UI, the final part of the sync function skipped")
return # can't update their UI # return # can't update their UI
if save_successful: # if save_successful:
logger.info("Metadata Saved Successfully") # logger.info("Metadata Saved Successfully")
client_observer.notify('synchronized', "Fetch & Save Complete!") # client_observer.notify('synchronized', "Fetch & Save Complete!")
else: # else:
client_observer.notify('synchronizing', "Saving List of Metadata Failed.") # client_observer.notify('synchronizing', "Saving List of Metadata Failed.")
@staticmethod @staticmethod

View file

@ -136,12 +136,10 @@ class ConnectionController:
try: try:
tor_module = TorModule(Constants.HV_TOR_STATE_HOME) tor_module = TorModule(Constants.HV_TOR_STATE_HOME)
tor_module.create_session(port_number, connection_observer) tor_module.create_session(port_number, connection_observer)
except TorServiceInitializationError as e:
logger.error(f"TorServiceInitializationError. Tor Can't Start: {e}")
if connection_observer is not None:
connection_observer.notify('custom_message', "Tor Can't Initialize")
except Exception as e: except Exception as e:
logger.error(f"Tor Can't Start: {e}") logger.error(f"Tor Can't Start: {e}")
if connection_observer is not None:
connection_observer.notify('custom_message', "Tor Can't Initialize")
@staticmethod @staticmethod
def terminate_tor_session_connection(port_number: int): def terminate_tor_session_connection(port_number: int):

View file

@ -165,12 +165,19 @@ def new_sync(client_observer: ClientObserver, connection_observer: ConnectionObs
if total_skipped == 0: if total_skipped == 0:
client_observer.notify('synchronized', "Fetch & Save Complete!") client_observer.notify('synchronized', "Fetch & Save Complete!")
save_successful = save_metadata(filtered_metadata) # the "save_data" function is inside sync_service save_successful = save_metadata(filtered_metadata)
if save_successful:
return Result(valid=True, message="Finshed sync.") return Result(valid=True, message="Finshed sync.")
else:
error_msg = "Finshed sync, but had issues with the saving of metadata for next time."
logger.error(error_msg)
return Result(valid=True, message=error_msg)
elif total_skipped < quantity_of_entries: elif total_skipped < quantity_of_entries:
error_msg = f"Partial Success. {total_skipped} skipped." error_msg = f"Partial Success. {total_skipped} skipped."
client_observer.notify('synchronized', error_msg) client_observer.notify('synchronized', error_msg)
return Result(valid=True, data=skipped, message=error_msg) return Result(valid=True, data=skipped, message=error_msg)
else: else:
error_msg = f"Sync Failed. All {total_skipped} entries were skipped!" error_msg = f"Sync Failed. All {total_skipped} entries were skipped!"
client_observer.notify('synchronized', error_msg) client_observer.notify('synchronized', error_msg)

View file

@ -11,7 +11,8 @@ from core.observers.BaseObserver import BaseObserver
from core.services.payment_phase.save_and_send_intitial_billing import save_and_send_intitial_billing from core.services.payment_phase.save_and_send_intitial_billing import save_and_send_intitial_billing
from core.services.networking.api_requests.ApiResponseModel import ApiResponse, ErrorType from core.services.networking.api_requests.ApiResponseModel import ApiResponse, ErrorType
from core.services.networking.api_requests.step5_solve_api_problems import solve_api_problems from core.services.networking.api_requests.step5_solve_api_problems import solve_api_problems
from core.errors.logger import logger
from core.errors.exceptions import ServerSideError, NetworkingError
from core.services.prepare_tickets.ticket_tracker import does_ticket_tracker_exist from core.services.prepare_tickets.ticket_tracker import does_ticket_tracker_exist
@ -132,7 +133,7 @@ def initiate_payment(
return invoice_data_object return invoice_data_object
except InvalidData as e: except ValueError as e:
error_msg = "Invalid Data." error_msg = "Invalid Data."
ticket_observer.notify("failed_input", subject=error_msg) ticket_observer.notify("failed_input", subject=error_msg)
invoice_data_object.add_error_code("invalid_data") invoice_data_object.add_error_code("invalid_data")

View file

@ -19,6 +19,7 @@ from core.services.helpers.get_value_from_config import get_value_from_config
from core.utils.basic_operations.does_file_exist import does_file_exist from core.utils.basic_operations.does_file_exist import does_file_exist
from core.utils.basic_operations.write_or_read_from_json import update_json from core.utils.basic_operations.write_or_read_from_json import update_json
from core.services.prepare_tickets.ticket_tracker import get_all_unused_tickets from core.services.prepare_tickets.ticket_tracker import get_all_unused_tickets
from core.errors.logger import logger
import random import random
@ -162,8 +163,10 @@ def use_ticket(
error_msg = f"Ticket is already tied to {location} with the subscription {subscription}" error_msg = f"Ticket is already tied to {location} with the subscription {subscription}"
ticket_observer.notify("failed_input", subject=error_msg) ticket_observer.notify("failed_input", subject=error_msg)
return {"valid": False, "message": error_msg} return {"valid": False, "message": error_msg}
except: except ValueError as e:
error_msg = f"Your local ticket tracker has no value for ticket {which_ticket}" error_msg = f"Your local ticket tracker has no value for ticket {which_ticket}"
logger.error(error_msg)
logger.error(str(e))
return {"valid": False, "message": error_msg} return {"valid": False, "message": error_msg}
# the actual work here, everything else is just handling: # the actual work here, everything else is just handling:

View file

@ -37,7 +37,7 @@ class Result():
def user_message(self) -> str: def user_message(self) -> str:
"""Human-readable error for the UI.""" """Human-readable error for the UI."""
messages = { messages = {
DBErrorType.SUCCESS: "Operation completed successfully.", ResultError.SUCCESS: "Operation completed successfully.",
DBErrorType.UNKNOWN: f"Error: {self.message}", ResultError.UNKNOWN: f"Error: {self.message}",
} }
return messages.get(self.error_type, "Unknown error") return messages.get(self.error_type, "Unknown error")

View file

@ -1,7 +1,7 @@
from core.Constants import Constants from core.Constants import Constants
from core.models.ClientVersion import ClientVersion from core.models.ClientVersion import ClientVersion
# from core.models.Location import Location from core.models.orm_models.Location import Location
# from core.models.Operator import Operator from core.models.orm_models.Operator import Operator
from core.models.Subscription import Subscription from core.models.Subscription import Subscription
from core.models.SubscriptionPlan import SubscriptionPlan from core.models.SubscriptionPlan import SubscriptionPlan
from core.models.invoice.Invoice import Invoice from core.models.invoice.Invoice import Invoice

View file

@ -13,6 +13,8 @@ from core.services.failed_verification.test_if_new_key_works import test_if_new_
from core.services.networking.make_url import make_url from core.services.networking.make_url import make_url
from core.services.networking.api_requests.step1_get_or_post import get_data_from_api from core.services.networking.api_requests.step1_get_or_post import get_data_from_api
from core.services.networking.httpx import connect
from core.services.networking.api_requests.ApiResponseModel import ApiResponse, ErrorType
# utils # utils
from core.utils.basic_operations.write_or_read_from_json import get_value_from_json_file from core.utils.basic_operations.write_or_read_from_json import get_value_from_json_file
@ -72,12 +74,21 @@ def get_new_pubkey_from_api(connection_observer: ConnectionObserver) -> dict | N
url = make_url(which_key_plan) url = make_url(which_key_plan)
# the result of this is a python dictionary with single ' # the result of this is a python dictionary with single '
api_results = get_data_from_server(url, None, connection_observer) # api_results = get_data_from_server(url, None, connection_observer)
api_results = connect.single_endpoint(
if "data" in api_results: method="get",
new_public_key = api_results["data"] url=url,
observer=connection_observer,
payload=None
)
if api_results.valid:
new_public_key = api_results.data
return new_public_key return new_public_key
else:
logger.error(f"API Results returned were invalid for that key.")
return None
def are_keys_different(old_public_key, new_public_key) -> bool: def are_keys_different(old_public_key, new_public_key) -> bool:

View file

@ -24,7 +24,7 @@ from core.errors.logger import logger
# generic # generic
import json, os import json, os
from typing import Any from typing import Any, Optional
import time import time

View file

@ -174,6 +174,7 @@ def quad9_proxy_dns_lookup(
domain: str, domain: str,
custom_proxy: str, custom_proxy: str,
timeout: int = 10, timeout: int = 10,
client_observer: ClientObserver = None
) -> str: ) -> str:
logger.debug("Doing a Proxy Quad9 DNS lookup") logger.debug("Doing a Proxy Quad9 DNS lookup")

View file

@ -11,10 +11,11 @@ from core.services.subscriptions.subscriptions import activate_subscription
from core.errors.logger import logger from core.errors.logger import logger
from core.errors.exceptions import * from core.errors.exceptions import *
from core.errors.exceptions import FirewallError
from typing import Union, Optional, Callable from typing import Union, Optional, Callable
from core.models.session.SessionProfile import SessionProfile from core.models.session.SessionProfile import SessionProfile
from core.models.system.SystemProfile import SystemProfile from core.models.system.SystemProfile import SystemProfile
from core.Errors import ConnectionTerminationError, InvalidSubscriptionError from core.Errors import ConnectionTerminationError, InvalidSubscriptionError, MissingSubscriptionError
from core.services.WebServiceApiService import WebServiceApiService from core.services.WebServiceApiService import WebServiceApiService
from core.controllers.ConnectionController import ConnectionController from core.controllers.ConnectionController import ConnectionController
from core.models.BaseProfile import ProfileType from core.models.BaseProfile import ProfileType

View file

@ -182,4 +182,4 @@ async def switch_get_and_post(method: str, url: str, client: httpx.Client, paylo
else: else:
# nevermind, # nevermind,
logger.info("Our strategy of switching GET/POST did NOT work.") logger.info("Our strategy of switching GET/POST did NOT work.")
return initial_result return second_result

View file

@ -35,8 +35,6 @@ def single_endpoint(method: str, url: str, observer: ConnectionObserver, payload
Try a request to a single endpoint using either an existing client, or creating a new one, then error handling. Try a request to a single endpoint using either an existing client, or creating a new one, then error handling.
""" """
global _port_used
connection_type = ConfigurationController.get_connection_enum() connection_type = ConfigurationController.get_connection_enum()
client = httpx_client.get_http_session() client = httpx_client.get_http_session()
@ -62,9 +60,6 @@ def single_endpoint(method: str, url: str, observer: ConnectionObserver, payload
######################################################## ########################################################
# FROM THIS POINT ON, WE HAVE A CLIENT # FROM THIS POINT ON, WE HAVE A CLIENT
######################################################## ########################################################
# #### SPOOF
# _port_used = 9050
# initial_result = ApiResponse(valid=False, error_type=ErrorType.DNS_TEMPORARY)
initial_result = make_request( initial_result = make_request(
method=method, method=method,
@ -367,3 +362,7 @@ def custom_dns_resolver_for_SINGLE_ENDPOINT(method: str, url: str, observer: Con
# """Merge two dictionaries. dict1 values take precedence on key collision.""" # """Merge two dictionaries. dict1 values take precedence on key collision."""
# return {**dict2, **dict1} # return {**dict2, **dict1}
def replace_http_with_https(url):
if url.startswith("http://"):
return url.replace("http://", "https://", 1)
return url

View file

@ -176,4 +176,4 @@ def switch_get_and_post(method: str, url: str, client: httpx.Client, payload: di
else: else:
# nevermind, # nevermind,
logger.info("Our strategy of switching GET/POST did NOT work.") logger.info("Our strategy of switching GET/POST did NOT work.")
return initial_result return second_result

View file

@ -16,6 +16,7 @@ from core.services.networking.regular_get_request import regular_get_request
from core.errors.exceptions import * from core.errors.exceptions import *
from core.errors.logger import logger from core.errors.logger import logger
import traceback import traceback
from typing import Optional
# Generic GET request to an endpoint, filtered by the user's preference of connection type (Tor or Not) # Generic GET request to an endpoint, filtered by the user's preference of connection type (Tor or Not)

View file

@ -84,13 +84,13 @@ def orchestrate_dns_check(target_interface: str) -> Result:
else: else:
logger.info(f"[DNS Orchestrator] Some of the DNS checks did NOT work. But this might be because the tunnel is down.") logger.info(f"[DNS Orchestrator] Some of the DNS checks did NOT work. But this might be because the tunnel is down.")
targets_not_found = 0 target_not_found = 0
for each_object in list_of_results_as_objects: for each_object in list_of_results_as_objects:
if each_object.error_type == SearchError.TARGET_MISSING: if each_object.error_type == SearchError.TARGET_MISSING:
target_not_found = target_not_found + 1 target_not_found = target_not_found + 1
return Result(valid=False, data=targets_not_found) return Result(valid=False, data=target_not_found)

View file

@ -1,6 +1,6 @@
from core.services.networking.systemwide.systemwide_errors import systemwide_hell_raiser from core.services.networking.systemwide.systemwide_errors import systemwide_hell_raiser
from core.utils.basic_operations.wrap_with import wrap_with from core.utils.basic_operations.wrap_with import wrap_with
from core.utils.run_commands import run_generic_command import run_generic_command from core.utils.run_commands import run_generic_command
from core.models.Result import Result, ResultError from core.models.Result import Result, ResultError
from core.errors.logger import logger from core.errors.logger import logger

View file

@ -10,6 +10,8 @@ from core.services.networking.systemwide.systemwide_utils import get_firewall_se
from core.services.networking.systemwide import dns from core.services.networking.systemwide import dns
from core.services.networking.systemwide.general_connection_tools.general_firewall_dns_tools import generic_enable_firewall_w_retry from core.services.networking.systemwide.general_connection_tools.general_firewall_dns_tools import generic_enable_firewall_w_retry
from core.errors.exceptions import FirewallError, DNSError from core.errors.exceptions import FirewallError, DNSError
from essentials.observers.ConnectionObserver import ConnectionObserver
# generic # generic
import subprocess import subprocess
@ -106,7 +108,7 @@ def start_singbox(
if not activation_result.valid: if not activation_result.valid:
error_msg = f"Singbox failed to start after {QUANTITY_OF_ATTEMPTS} attempts" error_msg = f"Singbox failed to start after {QUANTITY_OF_ATTEMPTS} attempts"
logger.error(f"[{function_name}] {error_msg}") logger.error(f"[{function_name}] {error_msg}")
return Result(valid=False, error_type=ResultError=PROCESS_WONT_START, message=error_msg) return Result(valid=False, error_type=ResultError.PROCESS_WONT_START, message=error_msg)
process_id = activation_result.data process_id = activation_result.data
time.sleep(2) time.sleep(2)
@ -129,7 +131,7 @@ def start_singbox(
) )
# ============= FIREWALL ============= # ============= FIREWALL =============
logger.info(f"[{function_name}] Attempting to enable the Firewall for {SINGBOX_TUN_IF} and {Constants.SINGBOX_INTERNAL_SUBNET}...") logger.info(f"[{function_name}] Attempting to enable the Firewall for {Constants.SINGBOX_TUN_IF} and {Constants.SINGBOX_INTERNAL_SUBNET}...")
# this is labeled "generic" for being protocol neutral # this is labeled "generic" for being protocol neutral
firewall_result = generic_enable_firewall_w_retry( firewall_result = generic_enable_firewall_w_retry(
interface_name=Constants.SINGBOX_TUN_IF, interface_name=Constants.SINGBOX_TUN_IF,

View file

@ -230,6 +230,7 @@ def _establish_connection_with_retry(
except ConnectionError as e: except ConnectionError as e:
# Unrecoverable error, fail immediately # Unrecoverable error, fail immediately
logger.error(str(e))
raise raise
except CalledProcessError as e: except CalledProcessError as e:

View file

@ -1,5 +1,7 @@
from core.utils.run_commands import run_generic_command from core.utils.run_commands import run_generic_command
from core.models.Result import Result, ResultError from core.models.Result import Result, ResultError
from core.errors.logger import logger
from subprocess import CalledProcessError from subprocess import CalledProcessError
import os import os
import re import re

View file

@ -1,4 +1,5 @@
from core.services.networking.tor_tools.monitor_bootstrap import monitor_bootstrap_progress from core.services.networking.tor_tools.monitor_bootstrap import monitor_bootstrap_progress
from core.services.networking.tor_tools.install_tor import install_tor
from core.services.networking.api_requests.ApiResponseModel import ApiResponse, ErrorType from core.services.networking.api_requests.ApiResponseModel import ApiResponse, ErrorType
from core.services.networking.tor_tools import ports from core.services.networking.tor_tools import ports
from core.Constants import Constants from core.Constants import Constants
@ -89,7 +90,7 @@ def bootstrap(
current_port = ports.get_random_available_port() current_port = ports.get_random_available_port()
use_new_folder = True use_new_folder = True
elif strategy == BootstrapStrategy.REINSTALL_AND_RETRY: elif strategy == BootstrapStrategy.REINSTALL_AND_RETRY:
if not install_tor().valid: if not install_tor(observer).valid:
return ApiResponse(valid=False, error_type=ErrorType.INSTALL_FAILED) return ApiResponse(valid=False, error_type=ErrorType.INSTALL_FAILED)
use_new_folder = True use_new_folder = True

View file

@ -27,7 +27,7 @@ def get_distro_package_manager() -> Optional[str]:
return None return None
async def install_tor() -> ApiResponse: async def install_tor(observer: ConnectionObserver) -> ApiResponse:
""" """
Prompt user to install Tor with pkexec, detecting distro for correct package manager. Prompt user to install Tor with pkexec, detecting distro for correct package manager.
""" """

View file

@ -7,13 +7,13 @@ from core.Constants import Constants
from typing import Optional from typing import Optional
import subprocess import subprocess
import asyncio import asyncio
import subprocess
import socket import socket
import httpx import httpx
from httpx_socks import AsyncProxyTransport from httpx_socks import AsyncProxyTransport
import json import json
import re import re
import os
import signal
def is_port_in_use(port: int) -> bool: def is_port_in_use(port: int) -> bool:
""" """

View file

@ -71,7 +71,7 @@ def get_bootstrap_port(port_tried: int, observer: ConnectionObserver):
def diagnose_tor_port(port_tried: int, observer: ConnectionObserver) -> ApiResponse: def diagnose_tor_port(port_tried: int, observer: ConnectionObserver) -> ApiResponse:
# Step 1) Is Tor Installed? # Step 1) Is Tor Installed?
if not is_installed('tor'): if not is_installed('tor'):
installed = install_tor() installed = install_tor(observer)
if installed: if installed:
return ApiResponse(valid=True, error_type=ErrorType.TOR_NOT_INSTALLED, port=Constants.DEFAULT_TOR_PORT) return ApiResponse(valid=True, error_type=ErrorType.TOR_NOT_INSTALLED, port=Constants.DEFAULT_TOR_PORT)
else: else:

View file

@ -35,7 +35,7 @@ def establish_tor_connection(observer: ConnectionObserver) -> ApiResponse:
# Step 2) Install Tor if needed. # Step 2) Install Tor if needed.
if result.error_type == ErrorType.TOR_NOT_INSTALLED: if result.error_type == ErrorType.TOR_NOT_INSTALLED:
installed = install_tor() installed = install_tor(observer)
if not installed: if not installed:
return ApiResponse(valid=False, error_type=ErrorType.REFUSAL_TO_INSTALL_TOR) return ApiResponse(valid=False, error_type=ErrorType.REFUSAL_TO_INSTALL_TOR)

View file

@ -11,6 +11,7 @@ from core.services.networking.api_requests.step1_get_or_post import send_data_to
from core.services.networking.api_requests.ApiResponseModel import ApiResponse, ErrorType from core.services.networking.api_requests.ApiResponseModel import ApiResponse, ErrorType
from core.services.networking.api_requests.step5_solve_api_problems import solve_api_problems from core.services.networking.api_requests.step5_solve_api_problems import solve_api_problems
from core.services.networking.httpx import connect
from core.services.networking.make_url import make_url from core.services.networking.make_url import make_url
from core.services.payment_phase.extract_payment_details import extract_payment_details from core.services.payment_phase.extract_payment_details import extract_payment_details
@ -42,22 +43,33 @@ def save_and_send_intitial_billing(
""" """
# Save choices: # Save choices:
save_billing_choices(payload) saved_choices = save_billing_choices(payload)
if not saved_choices:
error_msg = "Unable to save billing choices locally. Check file permissions and storage space."
logger.error(error_msg)
return TicketInvoice(is_valid=False, final_error_msg=error_msg)
# send them: # send them:
which_endpoint = "start_payment" which_endpoint = "start_payment"
url = make_url(which_endpoint) url = make_url(which_endpoint)
api_reply_object = send_data_to_server(payload, url, connection_observer) # api_reply_object = send_data_to_server(payload, url, connection_observer)
if not api_reply_object.valid: api_reply_object = connect.single_endpoint(
api_reply_object = solve_api_problems( method="post",
api_reply_object=api_reply_object,
get_or_post="post",
url=url, url=url,
payload=payload, observer=connection_observer,
connection_observer=connection_observer, payload=payload
client_observer=None
) )
# if not api_reply_object.valid:
# api_reply_object = solve_api_problems(
# api_reply_object=api_reply_object,
# get_or_post="post",
# url=url,
# payload=payload,
# connection_observer=connection_observer,
# client_observer=None
# )
if not api_reply_object.valid: if not api_reply_object.valid:
return api_reply_object return api_reply_object

View file

@ -8,4 +8,4 @@ def save_billing_choices(payload: dict) -> None:
billing_folder = Constants.HV_TICKETING_CONFIG_HOME billing_folder = Constants.HV_TICKETING_CONFIG_HOME
filepath = f"{billing_folder}/billing_choices.json" filepath = f"{billing_folder}/billing_choices.json"
write_json_to_file(payload, filepath) return write_json_to_file(payload, filepath)

View file

@ -7,6 +7,8 @@ from typing import Any
# services # services
from core.services.networking.make_url import make_url from core.services.networking.make_url import make_url
from core.services.networking.api_requests.step1_get_or_post import get_data_from_api from core.services.networking.api_requests.step1_get_or_post import get_data_from_api
from core.services.networking.httpx import connect
from core.services.networking.api_requests.ApiResponseModel import ApiResponse, ErrorType
# utils # utils
from core.utils.basic_operations.does_file_exist import does_file_exist from core.utils.basic_operations.does_file_exist import does_file_exist
@ -30,15 +32,17 @@ def get_from_server_and_save(
url = make_url(string_form_of_key_name) url = make_url(string_form_of_key_name)
# the result of this is a python dictionary with single ' # public_key_results = get_data_from_server(url, connection_observer)
public_key_results = get_data_from_server(url, connection_observer) public_key_results = connect.single_endpoint(
method="get",
url=url,
observer=connection_observer,
payload=None
)
if isinstance(public_key_results, dict) and "valid" in public_key_results: if public_key_results.valid:
status = public_key_results.get("valid", False)
if status == True:
# extract: # extract:
public_key = public_key_results.get("data", False) public_key = public_key_results.data
# save it: # save it:
did_it_save = write_string_to_text_file(public_key, file_path) did_it_save = write_string_to_text_file(public_key, file_path)

View file

@ -71,7 +71,7 @@ def get_public_key_by_config(connection_observer: ConnectionObserver) -> dict:
if reply in list_of_failures: if reply in list_of_failures:
return complete_failure_msg return complete_failure_msg
if not instance(reply, dict): if not isinstance(reply, dict):
return { return {
"status": False, "status": False,
"message": f"Server returned an invalid format, and even accessing via local files. Please check {filepath}", "message": f"Server returned an invalid format, and even accessing via local files. Please check {filepath}",
@ -141,7 +141,7 @@ def get_public_key_from_LOCAL_files_only(
if reply in list_of_failures: if reply in list_of_failures:
return complete_failure_msg return complete_failure_msg
if not instance(reply, dict): if not isinstance(reply, dict):
return { return {
"status": False, "status": False,
"message": f"Server returned an invalid format, and even accessing via local files. Please check {filepath}", "message": f"Server returned an invalid format, and even accessing via local files. Please check {filepath}",

View file

@ -21,4 +21,4 @@ def setup_ticket_tracker(how_many_profiles: int) -> None:
} }
counter += 1 counter += 1
write_json_to_file(ticket_data, ticket_tracker_path) return write_json_to_file(ticket_data, ticket_tracker_path)

View file

@ -94,9 +94,9 @@ def ticket_prep_orchestrator(
) )
# make a json to keep track of which tickets are used: # make a json to keep track of which tickets are used:
setup_ticket_tracker(how_many_profiles) setup_tracker = setup_ticket_tracker(how_many_profiles)
if did_prep_work: if did_prep_work and setup_tracker:
# this means it unblinded, & setup the tracker without erroring out, # this means it unblinded, & setup the tracker without erroring out,
# but it does NOT mean that verification of the blind sigs worked. # but it does NOT mean that verification of the blind sigs worked.
return {"valid": True, "message": "worked"} return {"valid": True, "message": "worked"}

View file

@ -1,7 +1,4 @@
from core.utils.basic_operations.write_or_read_from_json import ( from core.utils.basic_operations.write_or_read_from_json import read_entire_json
write_json_to_file,
read_entire_json,
)
from core.errors.exceptions import * from core.errors.exceptions import *
from core.errors.logger import logger from core.errors.logger import logger
from core.Constants import Constants from core.Constants import Constants
@ -62,7 +59,7 @@ def get_data_for_a_single_ticket(which_ticket_as_int: int) -> tuple:
error_msg = f"Entire file of tickets does not exist. Check the location {ticket_tracker_path}" error_msg = f"Entire file of tickets does not exist. Check the location {ticket_tracker_path}"
logger.error(error_msg, exc_info=True) logger.error(error_msg, exc_info=True)
print(error_msg) print(error_msg)
raise InvalidData(error_msg) raise ValueError(error_msg)
# the data is a string for lookups: # the data is a string for lookups:
which_ticket = str(which_ticket_as_int) which_ticket = str(which_ticket_as_int)
@ -74,6 +71,6 @@ def get_data_for_a_single_ticket(which_ticket_as_int: int) -> tuple:
subscription = data.get(which_ticket, {}).get("subscription") subscription = data.get(which_ticket, {}).get("subscription")
return status, location, subscription return status, location, subscription
else: else:
raise InvalidData( raise ValueError(
f"Key '{which_ticket}' does not exist in JSON file {ticket_tracker_path}" f"Key '{which_ticket}' does not exist in JSON file {ticket_tracker_path}"
) )

View file

@ -1,4 +1,3 @@
from core.errors.exceptions import *
from core.errors.logger import logger from core.errors.logger import logger
import json import json
@ -6,7 +5,7 @@ import os
from pathlib import Path from pathlib import Path
def write_json_to_file(data: dict, filepath: str) -> None: def write_json_to_file(data: dict, filepath: str) -> bool:
try: try:
# Create directory if it doesn't exist # Create directory if it doesn't exist
directory = os.path.dirname(filepath) directory = os.path.dirname(filepath)
@ -16,10 +15,20 @@ def write_json_to_file(data: dict, filepath: str) -> None:
with open(filepath, "w") as f: with open(filepath, "w") as f:
json.dump(data, f, indent=4) json.dump(data, f, indent=4)
return True
except TypeError as e: except TypeError as e:
raise TypeError(f"Data is not JSON serializable: {e}") logger.error(f"Data is not JSON serializable: {e}")
return False
except FileNotFoundError:
logger.error(f"File not found: {filepath}")
return False
except IsADirectoryError:
logger.error(f"Path is a directory, not a file: {filepath}")
return False
except IOError as e: except IOError as e:
raise IOError(f"Error writing to file {filepath}: {e}") logger.error(f"Error reading file {filepath}: {e}")
return False
def read_entire_json(filepath: str) -> dict: def read_entire_json(filepath: str) -> dict:
@ -43,13 +52,13 @@ def read_entire_json(filepath: str) -> dict:
f"Invalid JSON in file {filepath}: {e.msg}", e.doc, e.pos f"Invalid JSON in file {filepath}: {e.msg}", e.doc, e.pos
) )
except FileNotFoundError: except FileNotFoundError:
raise FileNotFoundError(f"File not found: {filepath}") logger.error(f"File not found: {filepath}")
return False return False
except IsADirectoryError: except IsADirectoryError:
raise IsADirectoryError(f"Path is a directory, not a file: {filepath}") logger.error(f"Path is a directory, not a file: {filepath}")
return False return False
except IOError as e: except IOError as e:
raise IOError(f"Error reading file {filepath}: {e}") logger.error(f"Error reading file {filepath}: {e}")
return False return False
@ -103,8 +112,14 @@ def update_value_in_json_with_two_values(
return True return True
except: except FileNotFoundError:
raise InvalidData(f"Error reading file {filepath}") logger.error(f"File not found: {filepath}")
return False
except IsADirectoryError:
logger.error(f"Path is a directory, not a file: {filepath}")
return False
except IOError as e:
logger.error(f"Error reading file {filepath}: {e}")
return False return False
@ -122,6 +137,12 @@ def update_json(filepath, key_to_add, value_to_update):
write_json_to_file(data, filepath) write_json_to_file(data, filepath)
return True return True
except: except FileNotFoundError:
raise InvalidData(f"Error reading file {filepath}") logger.error(f"File not found: {filepath}")
return False
except IsADirectoryError:
logger.error(f"Path is a directory, not a file: {filepath}")
return False
except IOError as e:
logger.error(f"Error reading file {filepath}: {e}")
return False return False

View file

@ -131,14 +131,14 @@ def run_generic_command(
try: try:
returncode, stdout = _run_command_via_terminal(command, timeout) returncode, stdout = _run_command_via_terminal(command, timeout)
output_data = stdout # output_data = stdout
if returncode == 0: if returncode == 0:
logger.info(f"{human_readable_goal} was successful") logger.info(f"{human_readable_goal} was successful")
return Result(valid=True, data=output_data) return Result(valid=True, data=stdout)
else: else:
# Try stderr first, fallback to stdout for error parsing # Try stderr first, fallback to stdout for error parsing
error_output = (stderr or stdout).strip() error_output = stdout.strip()
error_enum = parse_errors(error_output) error_enum = parse_errors(error_output)
logger.error(f"{human_readable_goal} Failed, error type is {error_enum}.") logger.error(f"{human_readable_goal} Failed, error type is {error_enum}.")
return Result(valid=False, error_type=error_enum, goal=human_readable_goal, message=error_output) return Result(valid=False, error_type=error_enum, goal=human_readable_goal, message=error_output)
@ -147,3 +147,19 @@ def run_generic_command(
return Result(valid=False, error_type=ResultError.TIMEOUT, goal=human_readable_goal, data=output_data, message=f"Command timed out {e}") return Result(valid=False, error_type=ResultError.TIMEOUT, goal=human_readable_goal, data=output_data, message=f"Command timed out {e}")
except Exception as e: except Exception as e:
return Result(valid=False, error_type=ResultError.UNKNOWN, goal=human_readable_goal, data=output_data, message=str(e)) return Result(valid=False, error_type=ResultError.UNKNOWN, goal=human_readable_goal, data=output_data, message=str(e))
def parse_errors(error_output: str) -> ResultError:
# Interface missing
if "No such device" in error_output:
error_enum = ResultError.INTERFACE
# Permission error
elif "No permissions" in error_output:
error_enum = ResultError.PERMISSION
elif "sudo: a password is required" or "password is required" in error_output:
error_enum = ResultError.PERMISSION
elif "command not found" in error_output:
error_enum = ResultError.MISSING_DEPENDENCY
else:
error_enum = ResultError.UNKNOWN
return error_enum