handOver2/database/sync_manager.py

289 lines
7.8 KiB
Python

# -*- coding: utf-8 -*-
"""
원격 데이터베이스 동기화 모듈
로컬 SQLite와 원격 Supabase 간의 데이터 동기화를 관리합니다.
현재는 프로토타입으로 인터페이스만 정의되어 있으며,
추후 Supabase 연동 시 구현될 예정입니다.
"""
from abc import ABC, abstractmethod
from datetime import datetime
from typing import Optional, List, Dict, Any
from enum import Enum
from core.logger import get_logger
from core.signals import get_signals
# 로거 설정
logger = get_logger(__name__)
class SyncStatus(Enum):
"""동기화 상태"""
IDLE = "idle"
SYNCING = "syncing"
SUCCESS = "success"
FAILED = "failed"
OFFLINE = "offline"
class SyncDirection(Enum):
"""동기화 방향"""
UPLOAD = "upload" # 로컬 -> 원격
DOWNLOAD = "download" # 원격 -> 로컬
BOTH = "both" # 양방향
class BaseSyncManager(ABC):
"""
동기화 관리자 추상 클래스
원격 데이터베이스와의 동기화 인터페이스를 정의합니다.
"""
@abstractmethod
def connect(self) -> bool:
"""원격 데이터베이스에 연결합니다."""
pass
@abstractmethod
def disconnect(self):
"""연결을 종료합니다."""
pass
@abstractmethod
def is_connected(self) -> bool:
"""연결 상태를 확인합니다."""
pass
@abstractmethod
def sync_table(self, table_name: str, direction: SyncDirection) -> bool:
"""테이블을 동기화합니다."""
pass
@abstractmethod
def sync_all(self, direction: SyncDirection) -> bool:
"""모든 테이블을 동기화합니다."""
pass
@abstractmethod
def get_last_sync_time(self, table_name: str = None) -> Optional[datetime]:
"""마지막 동기화 시간을 반환합니다."""
pass
class LocalOnlySyncManager(BaseSyncManager):
"""
로컬 전용 동기화 관리자 (프로토타입)
원격 연결 없이 로컬 데이터베이스만 사용합니다.
Supabase 연동 전까지 이 클래스를 사용합니다.
"""
def __init__(self):
"""초기화"""
self.signals = get_signals()
self._status = SyncStatus.OFFLINE
self._last_sync_time: Dict[str, datetime] = {}
logger.info("LocalOnlySyncManager 초기화 (원격 동기화 비활성화)")
def connect(self) -> bool:
"""
연결 시도 (항상 오프라인 상태)
Returns:
항상 False
"""
logger.info("원격 동기화가 비활성화되어 있습니다.")
self._status = SyncStatus.OFFLINE
return False
def disconnect(self):
"""연결 종료 (동작 없음)"""
pass
def is_connected(self) -> bool:
"""
연결 상태 확인
Returns:
항상 False
"""
return False
def sync_table(self, table_name: str, direction: SyncDirection) -> bool:
"""
테이블 동기화 (동작 없음)
Args:
table_name: 테이블 이름
direction: 동기화 방향
Returns:
항상 True (로컬 데이터는 항상 최신)
"""
self._last_sync_time[table_name] = datetime.now()
return True
def sync_all(self, direction: SyncDirection) -> bool:
"""
전체 동기화 (동작 없음)
Args:
direction: 동기화 방향
Returns:
항상 True
"""
logger.info("로컬 전용 모드: 동기화 건너뛰기")
return True
def get_last_sync_time(self, table_name: str = None) -> Optional[datetime]:
"""
마지막 동기화 시간 반환
Args:
table_name: 테이블 이름
Returns:
마지막 동기화 시간
"""
if table_name:
return self._last_sync_time.get(table_name)
return max(self._last_sync_time.values()) if self._last_sync_time else None
@property
def status(self) -> SyncStatus:
"""현재 동기화 상태"""
return self._status
class SupabaseSyncManager(BaseSyncManager):
"""
Supabase 동기화 관리자
추후 Supabase 연동 시 구현될 예정입니다.
Note:
이 클래스는 현재 스텁으로만 존재합니다.
실제 구현 시 supabase 패키지를 사용합니다.
"""
def __init__(self, url: str, key: str):
"""
초기화
Args:
url: Supabase 프로젝트 URL
key: Supabase API 키
"""
self.url = url
self.key = key
self.signals = get_signals()
self._client = None
self._status = SyncStatus.IDLE
self._last_sync_time: Dict[str, datetime] = {}
logger.info("SupabaseSyncManager 초기화 (추후 구현 예정)")
def connect(self) -> bool:
"""
Supabase에 연결합니다.
Returns:
연결 성공 여부
TODO:
supabase 패키지를 사용하여 실제 연결 구현
"""
# TODO: 실제 연결 구현
# from supabase import create_client
# self._client = create_client(self.url, self.key)
logger.warning("Supabase 연결 미구현")
return False
def disconnect(self):
"""연결을 종료합니다."""
self._client = None
self._status = SyncStatus.IDLE
def is_connected(self) -> bool:
"""연결 상태를 확인합니다."""
return self._client is not None
def sync_table(self, table_name: str, direction: SyncDirection) -> bool:
"""
테이블을 동기화합니다.
Args:
table_name: 테이블 이름
direction: 동기화 방향
Returns:
동기화 성공 여부
TODO:
- 마지막 동기화 시간 이후 변경된 레코드 조회
- 충돌 해결 로직 구현
- 배치 처리 구현
"""
# TODO: 실제 동기화 구현
logger.warning(f"테이블 동기화 미구현: {table_name}")
return False
def sync_all(self, direction: SyncDirection) -> bool:
"""
모든 테이블을 동기화합니다.
Args:
direction: 동기화 방향
Returns:
동기화 성공 여부
"""
tables = [
"instructions", "faults", "works", "miscs",
"daily_inspections", "todos", "memos"
]
success = True
for table in tables:
if not self.sync_table(table, direction):
success = False
if success:
self.signals.sync_completed.emit()
else:
self.signals.sync_error.emit("일부 테이블 동기화 실패")
return success
def get_last_sync_time(self, table_name: str = None) -> Optional[datetime]:
"""마지막 동기화 시간을 반환합니다."""
if table_name:
return self._last_sync_time.get(table_name)
return max(self._last_sync_time.values()) if self._last_sync_time else None
@property
def status(self) -> SyncStatus:
"""현재 동기화 상태"""
return self._status
def get_sync_manager() -> BaseSyncManager:
"""
동기화 관리자 인스턴스를 반환합니다.
현재는 LocalOnlySyncManager를 반환합니다.
추후 설정에 따라 SupabaseSyncManager를 반환할 수 있습니다.
Returns:
동기화 관리자 인스턴스
"""
# TODO: 설정에 따라 적절한 관리자 반환
return LocalOnlySyncManager()