Skip to content

Commit

Permalink
Support Default App Install & Arg Paths.
Browse files Browse the repository at this point in the history
  • Loading branch information
jreed1701 committed Dec 21, 2023
1 parent 105dbd9 commit a0d4aaf
Show file tree
Hide file tree
Showing 14 changed files with 153 additions and 40 deletions.
6 changes: 4 additions & 2 deletions application/api/v1/blueprints/access.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from flask import Blueprint, current_app, request, jsonify
from oauthlib.oauth2 import RequestValidator

from application.common import logger
from application.common import logger, constants
from application.common.authorization import _verify_bearer_token
from application.common.decorators import authorization_required
from application.common.exceptions import InvalidUsage
Expand Down Expand Up @@ -56,7 +56,9 @@ def token_generate():
if token_obj:
raise InvalidUsage("Error: Token by that name already exists!", status_code=400)

secret_obj = Settings.query.filter_by(setting_name="application_secret").first()
secret_obj = Settings.query.filter_by(
setting_name=constants.SETTING_NAME_APP_SECRET
).first()
validator = TokenValidator(secret_obj.setting_value, current_app.config["APP_NAME"])

computed_token = validator.generate_access_token(new_token_name)
Expand Down
5 changes: 4 additions & 1 deletion application/common/authorization.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from flask.wrappers import Request

from application.common import constants
from application.source.models.settings import Settings
from application.source.models.tokens import Tokens

Expand Down Expand Up @@ -32,7 +33,9 @@ def _verify_bearer_token(request: Request) -> int:
return 403

# Next decode this bad thing...
secret_obj = Settings.query.filter_by(setting_name="application_secret").first()
secret_obj = Settings.query.filter_by(
setting_name=constants.SETTING_NAME_APP_SECRET
).first()

try:
decoded_token = jwt.decode(
Expand Down
16 changes: 7 additions & 9 deletions application/common/constants.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import platform

from datetime import datetime
from enum import Enum

Expand All @@ -16,15 +14,15 @@ class FileModes(Enum):
DIRECTORY = 2


SETTING_NAME_STEAM_PATH: str = "steam_install_dir"
SETTING_NAME_DEFAULT_PATH: str = "default_install_dir"
SETTING_NAME_APP_SECRET: str = "application_secret"

NUM_SERVER_PROCESSES: int = 2

STARTUP_BATCH_FILE_NAME: str = "startup.bat"
DEFAULT_SECRET = str(datetime.now())

STARTUP_SETTINGS: dict = {
"steam_install_dir": r"C:\STEAM_TEST\steam"
if platform.system() == "Windows"
else "/opt/steam/steam_cmd",
"application_secret": DEFAULT_SECRET,
}
GAME_INSTALL_FOLDER = "games"

LOCALHOST_IP_ADDR = "127.0.0.1"
WAIT_FOR_BACKEND: int = 1
Expand Down
12 changes: 10 additions & 2 deletions application/common/game_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import shutil
import subprocess

from application.common import logger
from application.common import logger, constants
from application.common.game_argument import GameArgument
from application.common.exceptions import InvalidUsage
from application.extensions import DATABASE
Expand All @@ -14,7 +14,7 @@
class BaseGame:
DEFAULT_WAIT_PERIOD = 5

def __init__(self) -> None:
def __init__(self, defaults_dict: dict = {}) -> None:
self._game_args: dict = {}
self._game_name: str = None
self._game_pretty_name: str = None
Expand All @@ -23,6 +23,14 @@ def __init__(self) -> None:
self._game_installed: bool = False
self._game_info_url: str = ""

self._defaults = defaults_dict
self._game_default_install_dir = None

if constants.SETTING_NAME_DEFAULT_PATH in self._defaults:
self._game_default_install_dir = defaults_dict[
constants.SETTING_NAME_DEFAULT_PATH
]

@abc.abstractmethod
def startup(self) -> None:
"""Implementation Specific Startup Routine."""
Expand Down
4 changes: 2 additions & 2 deletions application/common/toolbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,11 @@ def _find_conforming_modules(package) -> {}:


@staticmethod
def _instantiate_object(module_name, module):
def _instantiate_object(module_name, module, defaults_dict={}):
return_obj = None
for item in inspect.getmembers(module, inspect.isclass):
if item[1].__module__ == module_name:
return_obj = item[1]()
return_obj = item[1](defaults_dict)
return return_obj


Expand Down
13 changes: 10 additions & 3 deletions application/config/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,14 @@ class DefaultConfig:
# App name and secret
APP_NAME = "AgentSmith"
APP_PRETTY_NAME = "Agent Smith"
DEPLOYMENT_TYPE = "python" # also supports kubernetes
APP_DEFAULT_SECRET = "super secret!"
DEPLOYMENT_TYPE = "python"

if platform.system() == "Windows":
DEFAULT_INSTALL_PATH = f"C:\\{APP_NAME}"
else:
# TODO - Revisit this when linux support gets closer...
DEFAULT_INSTALL_PATH = f"/usr/local/share/{APP_NAME}"

# Flask specific configs
DEBUG = True
Expand All @@ -20,14 +27,14 @@ class DefaultConfig:

# Designate where the database file is stored based on platform.
if platform.system() == "Windows":
base_folder = f"C:\\{APP_NAME}"
base_folder = DEFAULT_INSTALL_PATH
if not os.path.exists(base_folder):
os.makedirs(base_folder)
SQLALCHEMY_DATABASE_URI = f"sqlite:///{base_folder}\\{APP_NAME}.db"
else:
# Linux
# Right now, this is for testing since GitHub actions uses linux
SQLALCHEMY_DATABASE_URI = f"sqlite:///{APP_NAME}.db"
SQLALCHEMY_DATABASE_URI = f"sqlite:///{DEFAULT_INSTALL_PATH}/{APP_NAME}.db"

def __init__(self, deploy_type):
configuration_options = [el.value for el in _DeployTypes]
Expand Down
10 changes: 9 additions & 1 deletion application/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,17 @@ def create_app(config=None):

_handle_migrations(flask_app)

startup_settings: dict = {
constants.SETTING_NAME_STEAM_PATH: os.path.join(
flask_app.config["DEFAULT_INSTALL_PATH"], "steam"
),
constants.SETTING_NAME_DEFAULT_PATH: flask_app.config["DEFAULT_INSTALL_PATH"],
constants.SETTING_NAME_APP_SECRET: flask_app.config["APP_DEFAULT_SECRET"],
}

# Here just going to initialize some settings. TODO - Make into a function.
with flask_app.app_context():
for setting_name, setting_value in constants.STARTUP_SETTINGS.items():
for setting_name, setting_value in startup_settings.items():
setting_obj = Settings.query.filter_by(setting_name=setting_name).first()

if setting_obj is None:
Expand Down
1 change: 1 addition & 0 deletions application/gui/globals.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ def __init__(self):
self._server_host: str = "127.0.0.1"
self._server_port: str = "3000"
self._steam_install_path: str = "NOT_SET"
self._default_install_path: str = "NOT_SET"

# Objects
self._FLASK_APP: Flask = None
Expand Down
2 changes: 1 addition & 1 deletion application/gui/launch.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def _create_backend(self) -> Flask:
def _spawn_server_on_thread(self):
self._server_thread = Thread(
target=lambda: self._globals._FLASK_APP.run(
host="0.0.0.0", port=3000, debug=True, use_reloader=False
host="0.0.0.0", port=3000, debug=True, use_reloader=False, threaded=True
)
)
self._server_thread.daemon = True
Expand Down
10 changes: 9 additions & 1 deletion application/gui/widgets/file_select_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,19 @@

class FileSelectWidget(QWidget):
def __init__(
self, client: Operator, file_mode: FileModes, parent: QWidget = None
self,
client: Operator,
file_mode: FileModes,
parent: QWidget = None,
default_path=None,
) -> None:
super().__init__(parent)

self._parent = parent
self._client = client
self._file_mode: FileModes = file_mode
self._selected_path: str = ""
self._default_path = default_path

self.init_ui()

Expand Down Expand Up @@ -50,6 +55,9 @@ def init_ui(self):

self._layout.addLayout(selector_layout)

if self._default_path:
self._path_line_edit.setText(self._default_path)

self.setLayout(self._layout)

def get_line_edit(self) -> QLineEdit:
Expand Down
26 changes: 23 additions & 3 deletions application/gui/widgets/new_game_widget.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os
import time

from PyQt5.QtWidgets import (
Expand Down Expand Up @@ -47,6 +48,14 @@ def __init__(self, globals: GuiGlobals, parent: QWidget):
self._client, constants.FileModes.DIRECTORY, self
)

self._default_install_dir: str = self._client.app.get_setting_by_name(
constants.SETTING_NAME_DEFAULT_PATH
)

self._defaults: dict = {
constants.SETTING_NAME_DEFAULT_PATH: self._default_install_dir
}

self._initialized = False

def _build_inputs(self, game_name):
Expand All @@ -56,6 +65,7 @@ def _build_inputs(self, game_name):
input_frame_path_layout = QHBoxLayout()

game_object: BaseGame = self._supported_games[game_name]
game_short_name = game_object._game_name
required_args_dict = game_object._get_argument_dict()
args_list = []

Expand Down Expand Up @@ -83,10 +93,20 @@ def _build_inputs(self, game_name):
h_sep = QFrame()
h_sep.setFrameShape(QFrame.HLine)

# Compute a default game installation directory.
game_install_path = os.path.join(
self._default_install_dir, constants.GAME_INSTALL_FOLDER, game_short_name
)

# Add install path
install_path_layout = QHBoxLayout()
label = QLabel("Game Install Path: ")
text_edit = FileSelectWidget(self._client, constants.FileModes.DIRECTORY, self)
text_edit = FileSelectWidget(
self._client,
constants.FileModes.DIRECTORY,
self,
default_path=game_install_path,
)
self._current_game_install_path = text_edit
install_path_layout.addWidget(label)
install_path_layout.addWidget(text_edit)
Expand Down Expand Up @@ -116,7 +136,7 @@ def init_ui(self):

for module_name in modules_dict.keys():
game_obj = toolbox._instantiate_object(
module_name, modules_dict[module_name]
module_name, modules_dict[module_name], self._defaults
)
self._supported_games[game_obj._game_pretty_name] = game_obj
self._combo_box.addItem(game_obj._game_pretty_name)
Expand Down Expand Up @@ -165,7 +185,7 @@ def _install_game(self, game_pretty_name):
) # What the user actually input.
install_path = self._current_game_install_path.get_line_edit().text()
steam_install_dir = self._client.app.get_setting_by_name(
constants.STARTUP_STEAM_SETTING_NAME
constants.SETTING_NAME_STEAM_PATH
)

if install_path == "":
Expand Down
41 changes: 37 additions & 4 deletions application/gui/widgets/settings_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,15 @@ def __init__(self, client: Operator, globals: GuiGlobals, parent: QWidget = None
def init_ui(self):
self._layout.setAlignment(Qt.AlignTop)

steam_install_dir = self._client.app.get_setting_by_name("steam_install_dir")
application_secret = self._client.app.get_setting_by_name("application_secret")
steam_install_dir = self._client.app.get_setting_by_name(
constants.SETTING_NAME_STEAM_PATH
)
default_install_dir = self._client.app.get_setting_by_name(
constants.SETTING_NAME_DEFAULT_PATH
)
application_secret = self._client.app.get_setting_by_name(
constants.SETTING_NAME_APP_SECRET
)
self._globals._steam_install_path = steam_install_dir

self.tabs = QTabWidget()
Expand All @@ -43,6 +50,9 @@ def init_ui(self):

tab1_layout = QVBoxLayout()
tab1_layout.addLayout(self._create_steam_path_setting(steam_install_dir))
tab1_layout.addLayout(
self._create_default_install_path_setting(default_install_dir)
)
tab1_layout.addLayout(self._create_app_secret_setting(application_secret))
self.tab1.setLayout(tab1_layout)

Expand Down Expand Up @@ -72,6 +82,21 @@ def _create_steam_path_setting(self, steam_install_dir: str) -> QHBoxLayout:

return h_layout1

def _create_default_install_path_setting(
self, defaut_install_dir: str
) -> QHBoxLayout:
h_layout1 = QHBoxLayout()
label1 = QLabel("Default Install Path: ")
text_edit1 = FileSelectWidget(self._client, constants.FileModes.DIRECTORY, self)
text_edit1.get_line_edit().setText(defaut_install_dir)
text_edit1.get_line_edit().textChanged.connect(
self._update_default_install_path
)
h_layout1.addWidget(label1)
h_layout1.addWidget(text_edit1)

return h_layout1

def _create_app_secret_setting(self, application_secret: str) -> QHBoxLayout:
h_layout2 = QHBoxLayout()
label2 = QLabel("Application Secret: ")
Expand All @@ -87,8 +112,16 @@ def _update_steam_install_path(self, path):
logger.info(f"New Steam Install Path: {path}")
# TODO - Check if this is a path and not something garbage.
self._globals._steam_install_path = path
self._client.app.update_setting_by_name("steam_install_dir", path)
self._client.app.update_setting_by_name(constants.SETTING_NAME_STEAM_PATH, path)

def _update_default_install_path(self, path):
logger.info(f"New Default Install Path: {path}")
# TODO - Check if this is a path and not something garbage.
self._globals._default_install_path = path
self._client.app.update_setting_by_name(
constants.SETTING_NAME_DEFAULT_PATH, path
)

def _update_app_secret(self, text):
# TODO - Changing the app secret invalidates all existing tokens.
self._client.app.update_setting_by_name("application_secret", text)
self._client.app.update_setting_by_name(constants.SETTING_NAME_APP_SECRET, text)
18 changes: 13 additions & 5 deletions application/source/games/seven_dtd_game.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,10 @@
from application.extensions import DATABASE
from application.source.models.games import Games

# NOTE - This Game is not yet implemented.


class SevenDaysToDieGame(BaseGame):
def __init__(self) -> None:
super(SevenDaysToDieGame, self).__init__()
def __init__(self, defaults_dict: dict = {}) -> None:
super(SevenDaysToDieGame, self).__init__(defaults_dict)

self._game_name = "7dtd"
self._game_pretty_name = "7 Days To Die"
Expand All @@ -29,6 +27,16 @@ def __init__(self) -> None:

self._telnet = Telnet()

if self._game_default_install_dir:
default_config_file_path = os.path.join(
self._game_default_install_dir,
constants.GAME_INSTALL_FOLDER,
self._game_name,
"serverconfig.xml",
)
else:
default_config_file_path = None

# Add Args here, can update later.
self._add_argument(
GameArgument(
Expand All @@ -38,7 +46,7 @@ def __init__(self) -> None:
self._add_argument(
GameArgument(
"ServerConfigFilePath",
value=None,
value=default_config_file_path,
required=True,
is_permanent=True,
file_mode=constants.FileModes.FILE.value,
Expand Down
Loading

0 comments on commit a0d4aaf

Please sign in to comment.