summaryrefslogtreecommitdiff
path: root/py_modules
diff options
context:
space:
mode:
authorxXJSONDeruloXx <danielhimebauch@gmail.com>2025-07-21 23:04:08 -0400
committerxXJSONDeruloXx <danielhimebauch@gmail.com>2025-07-21 23:04:08 -0400
commite54b7e2c5f3a736f248353317007f922771ab0c7 (patch)
tree6fc8931d44b1fa93269d2bba89c9790bfd83fd7a /py_modules
parent2106ef8eb31ee46611fce07dd715d3ac1c4ca0ab (diff)
downloaddecky-lsfg-vk-e54b7e2c5f3a736f248353317007f922771ab0c7.tar.gz
decky-lsfg-vk-e54b7e2c5f3a736f248353317007f922771ab0c7.zip
refactor: remove unused backend files and improve configuration handling in TypeScript
Diffstat (limited to 'py_modules')
-rw-r--r--py_modules/lsfg_vk/base_service.py44
-rw-r--r--py_modules/lsfg_vk/config_schema.py105
-rw-r--r--py_modules/lsfg_vk/configuration.py78
-rw-r--r--py_modules/lsfg_vk/installation.py34
4 files changed, 122 insertions, 139 deletions
diff --git a/py_modules/lsfg_vk/base_service.py b/py_modules/lsfg_vk/base_service.py
index b595b07..b684ec9 100644
--- a/py_modules/lsfg_vk/base_service.py
+++ b/py_modules/lsfg_vk/base_service.py
@@ -5,10 +5,13 @@ Base service class with common functionality.
import os
import shutil
from pathlib import Path
-from typing import Any, Optional
+from typing import Any, Optional, TypeVar, Dict
from .constants import LOCAL_LIB, LOCAL_SHARE_BASE, VULKAN_LAYER_DIR, SCRIPT_NAME, CONFIG_DIR, CONFIG_FILENAME
+# Generic type for response dictionaries
+ResponseType = TypeVar('ResponseType', bound=Dict[str, Any])
+
class BaseService:
"""Base service class with common functionality"""
@@ -90,3 +93,42 @@ class BaseService:
except Exception:
self.log.error(f"Failed to write to {path}")
raise
+
+ def _success_response(self, response_type: type, message: str = "", **kwargs) -> Any:
+ """Create a standardized success response
+
+ Args:
+ response_type: The TypedDict response type to create
+ message: Success message
+ **kwargs: Additional response fields
+
+ Returns:
+ Success response dict
+ """
+ response = {
+ "success": True,
+ "message": message,
+ "error": None
+ }
+ response.update(kwargs)
+ return response
+
+ def _error_response(self, response_type: type, error: str, message: str = "", **kwargs) -> Any:
+ """Create a standardized error response
+
+ Args:
+ response_type: The TypedDict response type to create
+ error: Error description
+ message: Optional message
+ **kwargs: Additional response fields
+
+ Returns:
+ Error response dict
+ """
+ response = {
+ "success": False,
+ "message": message,
+ "error": error
+ }
+ response.update(kwargs)
+ return response
diff --git a/py_modules/lsfg_vk/config_schema.py b/py_modules/lsfg_vk/config_schema.py
index 4f036ff..39593ab 100644
--- a/py_modules/lsfg_vk/config_schema.py
+++ b/py_modules/lsfg_vk/config_schema.py
@@ -9,18 +9,28 @@ This module defines the complete configuration structure for lsfg-vk, managing T
"""
import re
+import sys
from typing import TypedDict, Dict, Any, Union, cast
from dataclasses import dataclass
from enum import Enum
from pathlib import Path
+# Import shared configuration constants
+sys.path.insert(0, str(Path(__file__).parent.parent.parent))
+from shared_config import CONFIG_SCHEMA_DEF, ConfigFieldType, get_field_names, get_defaults, get_field_types
-class ConfigFieldType(Enum):
- """Supported configuration field types"""
- BOOLEAN = "boolean"
- INTEGER = "integer"
- FLOAT = "float"
- STRING = "string"
+
+@dataclass
+class ConfigField:
+ """Configuration field definition"""
+ name: str
+ field_type: ConfigFieldType
+ default: Union[bool, int, float, str]
+ description: str
+
+ def get_toml_value(self, value: Union[bool, int, float, str]) -> Union[bool, int, float, str]:
+ """Get the value for TOML output"""
+ return value
@dataclass
@@ -36,51 +46,25 @@ class ConfigField:
return value
-# Configuration schema definition
+# Use shared configuration schema as source of truth
CONFIG_SCHEMA: Dict[str, ConfigField] = {
- "dll": ConfigField(
- name="dll",
- field_type=ConfigFieldType.STRING,
- default="", # Will be populated dynamically based on detection
- description="specify where Lossless.dll is stored"
- ),
-
- "multiplier": ConfigField(
- name="multiplier",
- field_type=ConfigFieldType.INTEGER,
- default=1,
- description="change the fps multiplier"
- ),
-
- "flow_scale": ConfigField(
- name="flow_scale",
- field_type=ConfigFieldType.FLOAT,
- default=0.8,
- description="change the flow scale"
- ),
-
- "performance_mode": ConfigField(
- name="performance_mode",
- field_type=ConfigFieldType.BOOLEAN,
- default=True,
- description="toggle performance mode"
- ),
-
- "hdr_mode": ConfigField(
- name="hdr_mode",
- field_type=ConfigFieldType.BOOLEAN,
- default=False,
- description="enable hdr mode"
- ),
-
- "experimental_present_mode": ConfigField(
- name="experimental_present_mode",
- field_type=ConfigFieldType.STRING,
- default="fifo",
- description="experimental: override vulkan present mode (fifo/mailbox/immediate)"
- ),
+ field_name: ConfigField(
+ name=field_def["name"],
+ field_type=ConfigFieldType(field_def["fieldType"]),
+ default=field_def["default"],
+ description=field_def["description"]
+ )
+ for field_name, field_def in CONFIG_SCHEMA_DEF.items()
}
+# Override DLL default to empty (will be populated dynamically)
+CONFIG_SCHEMA["dll"] = ConfigField(
+ name="dll",
+ field_type=ConfigFieldType.STRING,
+ default="", # Will be populated dynamically based on detection
+ description="specify where Lossless.dll is stored"
+)
+
# Fields that should ONLY be in the lsfg script, not in TOML config
SCRIPT_ONLY_FIELDS = {
"dxvk_frame_rate": ConfigField(
@@ -128,10 +112,16 @@ class ConfigurationManager:
@staticmethod
def get_defaults() -> ConfigurationData:
"""Get default configuration values"""
- return cast(ConfigurationData, {
+ # Use shared defaults and add script-only fields
+ shared_defaults = get_defaults()
+
+ # Add script-only fields that aren't in the shared schema
+ script_defaults = {
field.name: field.default
- for field in COMPLETE_CONFIG_SCHEMA.values()
- })
+ for field in SCRIPT_ONLY_FIELDS.values()
+ }
+
+ return cast(ConfigurationData, {**shared_defaults, **script_defaults})
@staticmethod
def get_defaults_with_dll_detection(dll_detection_service=None) -> ConfigurationData:
@@ -164,15 +154,18 @@ class ConfigurationManager:
@staticmethod
def get_field_names() -> list[str]:
"""Get ordered list of configuration field names"""
- return list(COMPLETE_CONFIG_SCHEMA.keys())
+ # Use shared field names and add script-only fields
+ shared_names = get_field_names()
+ script_names = list(SCRIPT_ONLY_FIELDS.keys())
+ return shared_names + script_names
@staticmethod
def get_field_types() -> Dict[str, ConfigFieldType]:
"""Get field type mapping"""
- return {
- field.name: field.field_type
- for field in CONFIG_SCHEMA.values()
- }
+ # Use shared field types and add script-only field types
+ shared_types = {name: ConfigFieldType(type_str) for name, type_str in get_field_types().items()}
+ script_types = {field.name: field.field_type for field in SCRIPT_ONLY_FIELDS.values()}
+ return {**shared_types, **script_types}
@staticmethod
def validate_config(config: Dict[str, Any]) -> ConfigurationData:
diff --git a/py_modules/lsfg_vk/configuration.py b/py_modules/lsfg_vk/configuration.py
index da765e0..47d0ebc 100644
--- a/py_modules/lsfg_vk/configuration.py
+++ b/py_modules/lsfg_vk/configuration.py
@@ -43,22 +43,12 @@ class ConfigurationService(BaseService):
# Merge TOML config with script values
config = ConfigurationManager.merge_config_with_script(toml_config, script_values)
- return {
- "success": True,
- "config": config,
- "message": None,
- "error": None
- }
+ return self._success_response(ConfigurationResponse, config=config)
except (OSError, IOError) as e:
error_msg = f"Error reading lsfg config: {str(e)}"
self.log.error(error_msg)
- return {
- "success": False,
- "config": None,
- "message": None,
- "error": str(e)
- }
+ return self._error_response(ConfigurationResponse, str(e), config=None)
except Exception as e:
error_msg = f"Error parsing config file: {str(e)}"
self.log.error(error_msg)
@@ -66,12 +56,9 @@ class ConfigurationService(BaseService):
from .dll_detection import DllDetectionService
dll_service = DllDetectionService(self.log)
config = ConfigurationManager.get_defaults_with_dll_detection(dll_service)
- return {
- "success": True,
- "config": config,
- "message": f"Using default configuration due to parse error: {str(e)}",
- "error": None
- }
+ return self._success_response(ConfigurationResponse,
+ f"Using default configuration due to parse error: {str(e)}",
+ config=config)
def update_config(self, dll: str, multiplier: int, flow_scale: float,
performance_mode: bool, hdr_mode: bool,
@@ -123,31 +110,18 @@ class ConfigurationService(BaseService):
f"dxvk_frame_rate={dxvk_frame_rate}, "
f"enable_wow64={enable_wow64}, disable_steamdeck_mode={disable_steamdeck_mode}")
- return {
- "success": True,
- "config": config,
- "message": "lsfg configuration updated successfully",
- "error": None
- }
+ return self._success_response(ConfigurationResponse,
+ "lsfg configuration updated successfully",
+ config=config)
except (OSError, IOError) as e:
error_msg = f"Error updating lsfg config: {str(e)}"
self.log.error(error_msg)
- return {
- "success": False,
- "config": None,
- "message": None,
- "error": str(e)
- }
+ return self._error_response(ConfigurationResponse, str(e), config=None)
except ValueError as e:
error_msg = f"Invalid configuration arguments: {str(e)}"
self.log.error(error_msg)
- return {
- "success": False,
- "config": None,
- "message": None,
- "error": str(e)
- }
+ return self._error_response(ConfigurationResponse, str(e), config=None)
def update_dll_path(self, dll_path: str) -> ConfigurationResponse:
"""Update just the DLL path in the configuration
@@ -183,22 +157,14 @@ class ConfigurationService(BaseService):
self.log.info(f"Updated DLL path in lsfg configuration: '{dll_path}'")
- return {
- "success": True,
- "config": config,
- "message": f"DLL path updated to: {dll_path}",
- "error": None
- }
+ return self._success_response(ConfigurationResponse,
+ f"DLL path updated to: {dll_path}",
+ config=config)
except Exception as e:
error_msg = f"Error updating DLL path: {str(e)}"
self.log.error(error_msg)
- return {
- "success": False,
- "config": None,
- "message": None,
- "error": str(e)
- }
+ return self._error_response(ConfigurationResponse, str(e), config=None)
def update_lsfg_script(self, config: ConfigurationData) -> ConfigurationResponse:
"""Update the ~/lsfg launch script with current configuration
@@ -217,22 +183,14 @@ class ConfigurationService(BaseService):
self.log.info(f"Updated lsfg launch script at {self.lsfg_script_path}")
- return {
- "success": True,
- "config": config,
- "message": "Launch script updated successfully",
- "error": None
- }
+ return self._success_response(ConfigurationResponse,
+ "Launch script updated successfully",
+ config=config)
except Exception as e:
error_msg = f"Error updating launch script: {str(e)}"
self.log.error(error_msg)
- return {
- "success": False,
- "config": None,
- "message": None,
- "error": str(e)
- }
+ return self._error_response(ConfigurationResponse, str(e), config=None)
def _generate_script_content(self, config: ConfigurationData) -> str:
"""Generate the content for the ~/lsfg launch script
diff --git a/py_modules/lsfg_vk/installation.py b/py_modules/lsfg_vk/installation.py
index 5bfc88b..b340093 100644
--- a/py_modules/lsfg_vk/installation.py
+++ b/py_modules/lsfg_vk/installation.py
@@ -43,7 +43,7 @@ class InstallationService(BaseService):
if not zip_path.exists():
error_msg = f"{ZIP_FILENAME} not found at {zip_path}"
self.log.error(error_msg)
- return {"success": False, "error": error_msg, "message": ""}
+ return self._error_response(InstallationResponse, error_msg, message="")
# Create directories if they don't exist
self._ensure_directories()
@@ -58,17 +58,17 @@ class InstallationService(BaseService):
self._create_lsfg_launch_script()
self.log.info("lsfg-vk installed successfully")
- return {"success": True, "message": "lsfg-vk installed successfully", "error": None}
+ return self._success_response(InstallationResponse, "lsfg-vk installed successfully")
except (OSError, zipfile.BadZipFile, shutil.Error) as e:
error_msg = f"Error installing lsfg-vk: {str(e)}"
self.log.error(error_msg)
- return {"success": False, "error": str(e), "message": ""}
+ return self._error_response(InstallationResponse, str(e), message="")
except Exception as e:
# Catch unexpected errors but log them separately
error_msg = f"Unexpected error installing lsfg-vk: {str(e)}"
self.log.error(error_msg)
- return {"success": False, "error": str(e), "message": ""}
+ return self._error_response(InstallationResponse, str(e), message="")
def _extract_and_install_files(self, zip_path: Path) -> None:
"""Extract zip file and install files to appropriate locations
@@ -209,30 +209,20 @@ class InstallationService(BaseService):
pass # Directory not empty or other error, ignore
if not removed_files:
- return {
- "success": True,
- "message": "No lsfg-vk files found to remove",
- "removed_files": None,
- "error": None
- }
+ return self._success_response(UninstallationResponse,
+ "No lsfg-vk files found to remove",
+ removed_files=None)
self.log.info("lsfg-vk uninstalled successfully")
- return {
- "success": True,
- "message": f"lsfg-vk uninstalled successfully. Removed {len(removed_files)} files.",
- "removed_files": removed_files,
- "error": None
- }
+ return self._success_response(UninstallationResponse,
+ f"lsfg-vk uninstalled successfully. Removed {len(removed_files)} files.",
+ removed_files=removed_files)
except OSError as e:
error_msg = f"Error uninstalling lsfg-vk: {str(e)}"
self.log.error(error_msg)
- return {
- "success": False,
- "message": "",
- "removed_files": None,
- "error": str(e)
- }
+ return self._error_response(UninstallationResponse, str(e),
+ message="", removed_files=None)
def cleanup_on_uninstall(self) -> None:
"""Clean up lsfg-vk files when the plugin is uninstalled"""