diff --git a/cli/__main__.py b/cli/__main__.py index fcd7f73..1c735a0 100644 --- a/cli/__main__.py +++ b/cli/__main__.py @@ -1,4 +1,149 @@ from core.Constants import Constants +from core.errors.logger import logger +from core.models.manage.session_management import init_session, get_session, close_session, create_ALL_tables, create_ONLY_db_version_table, get_path, does_it_exist, does_db_version_table_exist +from core.models.manage.version_check import check_database_compatibility, insert_new_version, get_custom_message +from core.services.helpers.manage_assets import assets_folder_setup +import os +import sys + +# ============================================================================ +# DISPLAY CHOICES AND RECOVERY UI +# ============================================================================ +def recovery_dialog(custom_error, db_version_you_have): + """This ends the app by forcing them to delete the database, move it, or just quit.""" + + print(custom_error) + print(""" + 1) Delete old database (won't harm existing profiles.) + + 2) Do nothing. Exit. + """ + ) + try: + choice = int(input("Enter your choice (1 or 2):")) + except: + print("must enter a number") + sys.exit() + + logger.info(f"[DB MANAGEMENT] From the database error options, the user picked {choice}") + + if choice == 1: + if os.path.exists(database_path): + os.remove(database_path) + logger.info(f"[DB MANAGEMENT] Deleted the DB file at {database_path}") + logger.info(f"[DB MANAGEMENT] Closing the app gracefully, for them to reboot..") + sys.exit() + + else: + logger.error(f"[DB MANAGEMENT] User opted to close the app WITHOUT wiping the database, even though they need to.") + sys.exit() + + +# ============================================================================ +# ASSETS FOLDER +# ============================================================================ +if not assets_folder_setup(): + custom_error = "Unable to Setup your Assets Folder. Please create an assets directory at ~/.local/share/hydra-veil/assets" + print(custom_error) + sys.exit() + +# ============================================================================ +# INITIALIZE DATABASE +# ============================================================================ +# Does the database exist? +system_path = get_path() +database_path = system_path / "storage.db" +main_db_exists = does_it_exist(database_path) + +# Setup operations on the main DB which create it +init_session() # (engine, Session, _session all initialized from session_management) +session = get_session() + +# does the version checker table exist? +version_table_exists = does_db_version_table_exist() + +# are they upgrading from a legacy version? +# that would mean the table existed, but not the version table, +if not version_table_exists and main_db_exists: + logger.info(f"[DB MANAGEMENT] We are dealing with a legacy database, we need to transition the user.") + + # shut down db connection + close_session() + + # THEN DISPLAY CHOICES AND RECOVERY UI + custom_error = "Upgrade Time! We transitioned to a new Database format for new features! Please delete the old version and fetch the new public data (what locations, browsers, ect) This will NOT affect your profiles or browser sessions." + db_version_you_have = "Old System" + recovery_dialog(custom_error, db_version_you_have) + sys.exit() + +# If they're still here, then if it's NOT a legacy version, + +# and the new version table doesn't exist, then create it: +if not version_table_exists: + create_ONLY_db_version_table() + +# ============================================================================ +# COMPARE DB VERISONS +# ============================================================================ +compatability_dict = check_database_compatibility(session) +reason = compatability_dict.get("reason", "error") +is_compatable = compatability_dict.get("result", False) +logger.info(f"[DB MANAGEMENT] The result of the check is {is_compatable} and the reason is {reason}") + +# ============================================================================ +# IF THE VERSIONS MATCH +# ============================================================================ +if is_compatable: + made_tables = create_ALL_tables() + + # SCREEN FAILED TABLES + if not made_tables: + custom_error = "Critical Failure with starting the models of the database." + logger.error(f"[DB MANAGEMENT] {custom_error}") + close_session() + choice = show_recovery_dialog({"message": custom_error, "db_version": 0, "status": "cant_make"}) + logger.info(f"[DB MANAGEMENT] From the database error options, the user picked {choice}") + sys.exit() + + # ASSUME TABLES CREATED + logger.info("[DB MANAGEMENT] Tables successfully made or initialized if pre-existing") + + # UPDATE DATA + did_it_insert = insert_new_version(session, Constants.DB_VERSION_THIS_APP_WANTS) + if not did_it_insert: + logger.error(f"[DB MANAGEMENT] Critical Failure with updating/inserting the new DB version into the database.") + + # Load GUI either way: + + # If the user lacks a database, we want to force them to sync the new data, to avoid NoneType errors when enabling existing profiles, + if reason == "no_database": + logger.info(f"[DB MANAGEMENT] User had no database to begin with, so now we're entering GUI with sync on..") + force_sync = True + else: + logger.info(f"[DB MANAGEMENT] Launcher is now passing it off to launch the main GUI window WITHOUT force sync..") + force_sync = False + +# ============================================================================ +# but IF the versions do NOT match +# ============================================================================ +else: + logger.error(f"[DB MANAGEMENT] The App is expecting a different DB version than the real database. The reason is {reason}") + db_version_you_have = compatability_dict.get("old_db_version", "Error getting the Version") + + # WHAT IS THE REASON? + custom_error = get_custom_message(reason, compatability_dict) + + # shut down db connection + close_session() + + # THEN DISPLAY CHOICES AND RECOVERY UI + recovery_dialog(custom_error, db_version_you_have) + +if force_sync: + print("You have to sync to avoid errors. Please run ./hydra-veil-x86_64.AppImage --cli sync") + +# continue with old flow: +# from core.Constants import Constants from core.Errors import MissingSubscriptionError, InvalidSubscriptionError, UnknownConnectionTypeError, ConnectionUnprotectedError, EndpointVerificationError, ProfileStateConflictError from core.controllers.ApplicationController import ApplicationController from core.controllers.ApplicationVersionController import ApplicationVersionController @@ -122,10 +267,18 @@ if __name__ == '__main__': profile_state_protection_parser = argparse.ArgumentParser(add_help=False) profile_state_protection_parser.add_argument('--without-profile-state-protection', action='store_true') + # Get the distribution object + distribution = metadata.distribution('sp-hydra-veil-cli') + main_parser = argparse.ArgumentParser(prog=distribution.name) - main_parser.add_argument('--version', '-v', action='version', version=f'{distribution.name} v{distribution.version}') + main_parser.add_argument('--version', '-v', action='version', + version=f'{distribution.name} v{distribution.version}') main_subparsers = main_parser.add_subparsers(title='commands', dest='command') + # main_parser = argparse.ArgumentParser(prog=distribution.name) + # main_parser.add_argument('--version', '-v', action='version', version=f'{distribution.name} v{distribution.version}') + # main_subparsers = main_parser.add_subparsers(title='commands', dest='command') + profile_parser = main_subparsers.add_parser('profile') profile_subparsers = profile_parser.add_subparsers(title='subcommands', dest='subcommand')