summaryrefslogtreecommitdiff
path: root/py_modules/lsfg_vk/base_service.py
blob: b684ec955fe563273bd6f1ff0dbaf8d53040c2cd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
"""
Base service class with common functionality.
"""

import os
import shutil
from pathlib import Path
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"""
    
    def __init__(self, logger: Optional[Any] = None):
        """Initialize base service
        
        Args:
            logger: Logger instance, defaults to decky.logger if None
        """
        if logger is None:
            import decky
            self.log = decky.logger
        else:
            self.log = logger
            
        # Initialize common paths using pathlib
        self.user_home = Path.home()
        self.local_lib_dir = self.user_home / LOCAL_LIB
        self.local_share_dir = self.user_home / VULKAN_LAYER_DIR
        self.lsfg_script_path = self.user_home / SCRIPT_NAME
        self.lsfg_launch_script_path = self.user_home / SCRIPT_NAME  # ~/lsfg launch script
        self.config_dir = self.user_home / CONFIG_DIR
        self.config_file_path = self.config_dir / CONFIG_FILENAME
    
    def _ensure_directories(self) -> None:
        """Create necessary directories if they don't exist"""
        self.local_lib_dir.mkdir(parents=True, exist_ok=True)
        self.local_share_dir.mkdir(parents=True, exist_ok=True)
        self.config_dir.mkdir(parents=True, exist_ok=True)
        self.log.info(f"Ensured directories exist: {self.local_lib_dir}, {self.local_share_dir}, {self.config_dir}")
    
    def _remove_if_exists(self, path: Path) -> bool:
        """Remove a file if it exists
        
        Args:
            path: Path to the file to remove
            
        Returns:
            True if file was removed, False if it didn't exist
            
        Raises:
            OSError: If removal fails
        """
        if path.exists():
            try:
                path.unlink()
                self.log.info(f"Removed {path}")
                return True
            except OSError as e:
                self.log.error(f"Failed to remove {path}: {e}")
                raise
        else:
            self.log.info(f"File not found: {path}")
            return False
    
    def _write_file(self, path: Path, content: str, mode: int = 0o644) -> None:
        """Write content to a file
        
        Args:
            path: Target file path
            content: Content to write
            mode: File permissions (default: 0o644)
            
        Raises:
            OSError: If write fails
        """
        try:
            # Write directly to the file
            with open(path, 'w', encoding='utf-8') as f:
                f.write(content)
                f.flush()  # Ensure data is written to disk
                os.fsync(f.fileno())  # Force filesystem sync
            
            # Set permissions
            path.chmod(mode)
            self.log.info(f"Wrote to {path}")
            
        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