AutoPercenty3/main.py

249 lines
8.7 KiB
Python

import multiprocessing as mp
import sys
import ctypes
import os
import time
import logging
import atexit
from PySide6.QtWidgets import QApplication, QMessageBox
from PySide6.QtGui import QIcon
from sleep_control import prevent_sleep_mode, restore_sleep_mode
from login_dialog import LoginDialog
from mainUI_SP import MAIN_GUI
from limited_gui import shuffleMAIN_GUI
from src.modules.settings_manager import SettingsManager
from loggerModule import Logger
from src.loggerModules.loggerModule_structlog import StructlogImprovedLogger
from updateManager.__version__ import __file_log_level__, __gui_log_level__, __version__
import socket
# Windows DPI Awareness Constants
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 = -4
# 윈도우 플랫폼 여부 확인
IS_WIN = sys.platform.startswith('win')
def is_already_running(port=56387):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.bind(("127.0.0.1", port))
return False # 정상 바인딩 = 최초 실행
except OSError:
return True # 이미 바인딩 되어 있음 = 실행 중
def run_single_instance_check(logger):
# 포트 / Mutex 두 방식 모두 여기로 이동
if is_already_running():
app = QApplication([])
logger.log("이미 프로그램이 실행 중입니다! - 중복실행", level=logging.INFO)
QMessageBox.warning(None, "중복 실행", "이미 프로그램이 실행 중입니다!")
sys.exit(0)
# Mutex 방식
try:
import win32event, win32api, winerror
mutex = win32event.CreateMutex(None, False, "Edit_PartTimer3Mutex")
if win32api.GetLastError() == winerror.ERROR_ALREADY_EXISTS:
app = QApplication([])
QMessageBox.warning(None, "중복 실행", "이미 프로그램이 실행 중입니다!")
sys.exit(0)
except ImportError:
pass
def set_dpi_awareness():
"""애플리케이션 DPI 설정"""
try:
ctypes.windll.shcore.SetProcessDpiAwareness(1) # 프로세스 DPI 인식 설정
except Exception:
pass # Windows가 아니거나 실패할 경우 무시
# COM 초기화·해제 헬퍼
def initialize_com():
"""Win32 OLE(COM) 라이브러리 초기화"""
ctypes.windll.ole32.OleInitialize(None)
def uninitialize_com():
"""Win32 OLE(COM) 라이브러리 해제"""
ctypes.windll.ole32.OleUninitialize()
def get_application_path():
"""
애플리케이션 실행 경로를 반환합니다.
개발 환경과 패키지 배포 환경 모두에서 작동합니다.
"""
if getattr(sys, 'frozen', False): # 패키징된 경우
base_dir = os.path.dirname(sys.executable)
internal_dir = os.path.join(base_dir, 'lib', 'src') # lib 디렉토리 포함
if os.path.exists(internal_dir): # lib 디렉토리가 존재하면 base_dir로 설정
return internal_dir
else: # 일반 Python 실행 환경
base_dir = os.path.dirname(os.path.abspath(__file__))
debug_dir = os.path.join(base_dir, 'src') # lib 디렉토리 포함
return debug_dir
def setup_logging():
"""
로그 디렉토리와 파일을 설정하고 경로를 반환합니다.
"""
base_path = get_application_path()
logs_dir = os.path.join(base_path, "logs")
# 로그 디렉토리 생성 (존재하지 않는 경우)
try:
if not os.path.exists(logs_dir):
os.makedirs(logs_dir)
print(f"로그 디렉토리 생성됨: {logs_dir}")
except Exception as e:
print(f"로그 디렉토리 생성 실패: {e}")
logs_dir = base_path # 실패 시 기본 경로 사용
log_file_path = os.path.join(logs_dir, "Edit_PartTimer3.log")
# # 로그 파일 경로 출력 (디버깅용)
# print(f"로그 파일 경로: {log_file_path}")
return {
"logs_dir": logs_dir,
"log_file_path": log_file_path
}
def main():
# 로그 설정
log_paths = setup_logging()
# 로거 초기화 - 경로 정보 활용
logger = Logger(
log_file=log_paths["log_file_path"],
logger_name="EP3_Logger",
file_log_level=__file_log_level__
)
try:
if mp.current_process().name == "MainProcess":
run_single_instance_check(logger)
except ImportError:
pass
logger.log("===== 프로그램 시작 =====", level=logging.INFO)
logger.log(f"로그 파일 경로: {log_paths['log_file_path']}", level=logging.INFO)
settings_manager = SettingsManager(logger=logger, organization="WhenRideMycar", application="EditPartTimer3")
# DPI 관련 경고 제거 (Qt 기본값 설정)
set_dpi_awareness()
# ▶ COM 초기화 (한 번만 실행)
initialize_com()
"""프로그램 시작점"""
app = QApplication([])
# 애플리케이션 아이콘 설정
try:
app_path = get_application_path()
icon_path = os.path.join(app_path, "Edit_PartTimer3.ico")
if os.path.exists(icon_path):
app.setWindowIcon(QIcon(icon_path))
logger.log(f"애플리케이션 아이콘 설정: {icon_path}", level=logging.INFO)
else:
logger.log(f"아이콘 파일을 찾을 수 없습니다: {icon_path}", level=logging.WARNING)
except Exception as e:
logger.log(f"아이콘 설정 실패: {e}", level=logging.ERROR)
# 슬립 방지 활성화
prevent_sleep_mode()
# 업데이트 여부 체크
changelog = ''
# 로그인 다이얼로그 실행 (모달)
login_dialog = LoginDialog(logger, settings_manager)
if login_dialog.exec() == LoginDialog.Accepted:
user_info = login_dialog.get_user_info()
supabase_manager = login_dialog.get_supabase_manager()
system_info = login_dialog.get_system_info()
run_type = login_dialog.get_run_type() # <- 추가
update_selection_data = login_dialog.get_update_selection_data() # 업데이트 선택 정보 추가
logger.log(f"run_type: {run_type}", level=logging.INFO)
logger.log(f"update_selection: {update_selection_data}", level=logging.DEBUG)
# run_type 값에 따라 분기
if run_type == "편집알바생":
# 알바생소집: 기존 메인UI 실행
mainWindow = MAIN_GUI(
logger=logger,
user_info=user_info,
supabase_manager=supabase_manager,
settings_manager=settings_manager,
system_info=system_info,
update_log=changelog,
app=app,
version=__version__,
log_paths=log_paths
)
logger.log("편집알바생 실행", level=logging.INFO)
if run_type == "업로드알바생":
mainWindow = shuffleMAIN_GUI(
logger=logger,
user_info=user_info,
supabase_manager=supabase_manager,
settings_manager=settings_manager,
system_info=system_info,
update_log=changelog,
app=app,
version=__version__,
log_paths=log_paths
)
logger.log("업로드알바생 실행", level=logging.INFO)
else:
sys.exit("로그인 실패 또는 취소되었습니다.")
# 윈도우에도 아이콘 설정
try:
app_path = get_application_path()
icon_path = os.path.join(app_path, "Edit_PartTimer3.ico")
if os.path.exists(icon_path):
app_icon = QIcon(icon_path)
mainWindow.setWindowIcon(app_icon)
logger.log("메인 윈도우에 아이콘 설정 완료", level=logging.INFO)
except Exception as e:
logger.log(f"메인 윈도우 아이콘 설정 실패: {e}", level=logging.ERROR)
# 애플리케이션 종료 시 세션 정리 코드 추가
def cleanup_on_exit():
# 프로그램 종료 시 COM 해제
atexit.register(uninitialize_com)
# 세션 종료 처리
try:
logger.log(f"프로그램 종료: 현재 세션 종료 중 ...", level=logging.INFO)
# 세션 종료
supabase_manager.close_session()
# # 저장된 세션 ID 제거
# settings_manager.remove_session_id()
logger.log("세션이 성공적으로 종료되었습니다.", level=logging.INFO)
except Exception as e:
logger.log(f"세션 종료 오류: {e}", level=logging.ERROR)
# 슬립 모드 복원
restore_sleep_mode()
# 애플리케이션 종료 이벤트 연결
app.aboutToQuit.connect(cleanup_on_exit)
mainWindow.show()
sys.exit(app.exec())
if __name__ == "__main__":
import multiprocessing as mp
mp.freeze_support() # ← 추가
main()