summaryrefslogtreecommitdiff
path: root/lsfg_vk/base_service.py
blob: b54775993905dc783d0c4c134cc37660772d5028 (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
"""
Base service class with common functionality.
"""

import os
import shutil
import tempfile
from pathlib import Path
from typing import Any, Optional

from .constants import LOCAL_LIB, LOCAL_SHARE_BASE, VULKAN_LAYER_DIR, SCRIPT_NAME


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
    
    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.log.info(f"Ensured directories exist: {self.local_lib_dir}, {self.local_share_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 _atomic_write(self, path: Path, content: str, mode: int = 0o644) -> None:
        """Write content to a file atomically
        
        Args:
            path: Target file path
            content: Content to write
            mode: File permissions (default: 0o644)
            
        Raises:
            OSError: If write fails
        """
        # Create temporary file in the same directory to ensure atomic move
        temp_path = None
        try:
            with tempfile.NamedTemporaryFile(
                mode='w', 
                dir=path.parent, 
                delete=False,
                prefix=f'.{path.name}.',
                suffix='.tmp'
            ) as temp_file:
                temp_file.write(content)
                temp_path = Path(temp_file.name)
            
            # Set permissions before moving
            temp_path.chmod(mode)
            
            # Atomic move
            temp_path.replace(path)
            self.log.info(f"Atomically wrote to {path}")
            
        except Exception:
            # Clean up temp file if something went wrong
            if temp_path and temp_path.exists():
                try:
                    temp_path.unlink()
                except OSError:
                    pass  # Best effort cleanup
            raise