- Add MATTERMOST_ENABLED, TELEGRAM_ENABLED, SYNOLOGY_ENABLED, NOTION_ENABLED, GA4_ENABLED flags - Skip disabled platforms in message_sender.py - Comment out unused config variables in .env.sample - Add .vscode settings for virtual environment debugging
273 lines
9.4 KiB
Python
273 lines
9.4 KiB
Python
# ===================================================================
|
|
# core/config.py
|
|
# FGTools 통합 설정 관리 모듈
|
|
# ===================================================================
|
|
# 환경변수(.env)를 기반으로 모든 설정을 통합 관리합니다.
|
|
# python-dotenv를 사용하여 .env 파일을 자동으로 로드합니다.
|
|
# ===================================================================
|
|
"""
|
|
FGTools 설정 관리 모듈
|
|
|
|
환경변수 기반의 통합 설정 관리를 제공합니다.
|
|
.env 파일에서 설정을 로드하고, 기본값 및 타입 변환을 지원합니다.
|
|
|
|
사용 예시:
|
|
from core.config import get_config
|
|
config = get_config()
|
|
db_host = config.database['host']
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
from typing import Any, Dict, List, Optional
|
|
from functools import lru_cache
|
|
|
|
# .env 파일 로드
|
|
try:
|
|
from dotenv import load_dotenv
|
|
load_dotenv()
|
|
except ImportError:
|
|
pass
|
|
|
|
|
|
class Config:
|
|
"""
|
|
환경변수 기반 설정 관리 클래스
|
|
|
|
모든 설정은 환경변수에서 로드되며, 기본값을 제공합니다.
|
|
민감한 정보는 .env 파일에 저장하고 .gitignore에 추가하세요.
|
|
"""
|
|
|
|
def __init__(self):
|
|
"""설정 초기화 및 환경변수 로드"""
|
|
self._load_all_configs()
|
|
|
|
def _get_env(self, key: str, default: str = '', required: bool = False) -> str:
|
|
"""
|
|
환경변수 조회
|
|
|
|
Args:
|
|
key: 환경변수 키
|
|
default: 기본값
|
|
required: 필수 여부 (True면 없을 시 에러)
|
|
|
|
Returns:
|
|
환경변수 값
|
|
|
|
Raises:
|
|
SystemExit: 필수 환경변수가 없을 경우
|
|
"""
|
|
value = os.getenv(key, default)
|
|
if required and not value:
|
|
print(f"[ERROR] 필수 환경변수가 설정되지 않았습니다: {key}")
|
|
sys.exit(1)
|
|
return value
|
|
|
|
def _get_bool(self, key: str, default: bool = False) -> bool:
|
|
"""환경변수를 불리언으로 변환"""
|
|
return self._get_env(key, str(default)).lower() in ('true', '1', 'yes')
|
|
|
|
def _get_int(self, key: str, default: int = 0) -> int:
|
|
"""환경변수를 정수로 변환"""
|
|
try:
|
|
return int(self._get_env(key, str(default)))
|
|
except ValueError:
|
|
return default
|
|
|
|
def _get_float(self, key: str, default: float = 0.0) -> float:
|
|
"""환경변수를 실수로 변환"""
|
|
try:
|
|
return float(self._get_env(key, str(default)))
|
|
except ValueError:
|
|
return default
|
|
|
|
def _get_list(self, key: str, default: str = '', separator: str = ',') -> List[str]:
|
|
"""환경변수를 리스트로 변환 (구분자로 분리)"""
|
|
value = self._get_env(key, default)
|
|
return [item.strip() for item in value.split(separator) if item.strip()]
|
|
|
|
def _get_int_list(self, key: str, default: str = '') -> List[int]:
|
|
"""환경변수를 정수 리스트로 변환"""
|
|
str_list = self._get_list(key, default)
|
|
result = []
|
|
for item in str_list:
|
|
try:
|
|
result.append(int(item))
|
|
except ValueError:
|
|
continue
|
|
return result
|
|
|
|
def _load_all_configs(self):
|
|
"""모든 설정 로드"""
|
|
# 공통 설정
|
|
self.debug = self._get_bool('DEBUG', False)
|
|
self.log_level = self._get_env('LOG_LEVEL', 'INFO')
|
|
self.max_workers = self._get_int('MAX_WORKERS', 4)
|
|
|
|
# 데이터베이스 설정
|
|
self.database = {
|
|
'host': self._get_env('DB_HOST', 'localhost'),
|
|
'user': self._get_env('DB_USER', 'firstgarden'),
|
|
'password': self._get_env('DB_PASSWORD', ''),
|
|
'name': self._get_env('DB_NAME', 'firstgarden'),
|
|
'charset': self._get_env('DB_CHARSET', 'utf8mb4'),
|
|
}
|
|
|
|
self.table_prefix = self._get_env('TABLE_PREFIX', 'fg_manager_static_')
|
|
|
|
# 공공데이터포털 API 설정
|
|
self.data_api = {
|
|
'service_key': self._get_env('DATA_API_SERVICE_KEY', ''),
|
|
'start_date': self._get_env('DATA_API_START_DATE', '20170101'),
|
|
'end_date': self._get_env('DATA_API_END_DATE', '20250701'),
|
|
'air_stations': self._get_list('AIR_STATION_NAMES', '운정'),
|
|
'weather_station_ids': self._get_int_list('WEATHER_STN_IDS', '99'),
|
|
}
|
|
|
|
# GA4 설정
|
|
self.ga4 = {
|
|
'enabled': self._get_bool('GA4_ENABLED', False),
|
|
'api_token': self._get_env('GA4_API_TOKEN', ''),
|
|
'property_id': self._get_int('GA4_PROPERTY_ID', 0),
|
|
'service_account_file': self._get_env('GA4_SERVICE_ACCOUNT_FILE', './conf/service-account-credentials.json'),
|
|
'start_date': self._get_env('GA4_START_DATE', '20170101'),
|
|
'end_date': self._get_env('GA4_END_DATE', '20990731'),
|
|
'max_rows_per_request': self._get_int('GA4_MAX_ROWS_PER_REQUEST', 10000),
|
|
}
|
|
|
|
# POS 설정
|
|
self.pos = {
|
|
'visitor_categories': self._get_list('VISITOR_CATEGORIES', '입장료,티켓,기업제휴'),
|
|
}
|
|
|
|
# UPSolution 설정
|
|
self.upsolution = {
|
|
'id': self._get_env('UPSOLUTION_ID', ''),
|
|
'code': self._get_env('UPSOLUTION_CODE', ''),
|
|
'pw': self._get_env('UPSOLUTION_PW', ''),
|
|
}
|
|
|
|
# 예측 가중치 설정
|
|
self.forecast_weight = {
|
|
'visitor_multiplier': self._get_float('FORECAST_VISITOR_MULTIPLIER', 0.5),
|
|
'min_temp': self._get_float('FORECAST_WEIGHT_MIN_TEMP', 1.0),
|
|
'max_temp': self._get_float('FORECAST_WEIGHT_MAX_TEMP', 1.0),
|
|
'precipitation': self._get_float('FORECAST_WEIGHT_PRECIPITATION', 10.0),
|
|
'humidity': self._get_float('FORECAST_WEIGHT_HUMIDITY', 1.0),
|
|
'pm25': self._get_float('FORECAST_WEIGHT_PM25', 1.0),
|
|
'holiday': self._get_int('FORECAST_WEIGHT_HOLIDAY', 20),
|
|
}
|
|
|
|
self.force_update = self._get_bool('FORCE_UPDATE', False)
|
|
|
|
# Weather 서비스 설정
|
|
self.weather_service = {
|
|
'service_key': self._get_env('SERVICE_KEY', ''),
|
|
}
|
|
|
|
# FTP 설정
|
|
self.ftp = {
|
|
'host': self._get_env('FTP_HOST', ''),
|
|
'user': self._get_env('FTP_USER', ''),
|
|
'password': self._get_env('FTP_PASSWORD', ''),
|
|
'upload_dir': self._get_env('FTP_UPLOAD_DIR', ''),
|
|
}
|
|
|
|
# 게시판 설정
|
|
self.board = {
|
|
'id': self._get_env('BOARD_ID', ''),
|
|
'ca_name': self._get_env('BOARD_CA_NAME', ''),
|
|
'content': self._get_env('BOARD_CONTENT', ''),
|
|
'mb_id': self._get_env('BOARD_MB_ID', ''),
|
|
'nickname': self._get_env('BOARD_NICKNAME', ''),
|
|
}
|
|
|
|
# Mattermost 설정
|
|
self.mattermost = {
|
|
'enabled': self._get_bool('MATTERMOST_ENABLED', False),
|
|
'url': self._get_env('MATTERMOST_URL', ''),
|
|
'token': self._get_env('MATTERMOST_TOKEN', ''),
|
|
'channel_id': self._get_env('MATTERMOST_CHANNEL_ID', ''),
|
|
'webhook_url': self._get_env('MATTERMOST_WEBHOOK_URL', ''),
|
|
}
|
|
|
|
# Telegram 설정
|
|
self.telegram = {
|
|
'enabled': self._get_bool('TELEGRAM_ENABLED', False),
|
|
'bot_token': self._get_env('TELEGRAM_BOT_TOKEN', ''),
|
|
'chat_id': self._get_env('TELEGRAM_CHAT_ID', ''),
|
|
}
|
|
|
|
# Synology Chat 설정
|
|
self.synology = {
|
|
'enabled': self._get_bool('SYNOLOGY_ENABLED', False),
|
|
'chat_url': self._get_env('SYNOLOGY_CHAT_URL', ''),
|
|
'chat_token': self._get_env('SYNOLOGY_CHAT_TOKEN', ''),
|
|
}
|
|
|
|
# Notion 설정
|
|
self.notion = {
|
|
'enabled': self._get_bool('NOTION_ENABLED', False),
|
|
'api_secret': self._get_env('NOTION_API_SECRET', ''),
|
|
}
|
|
|
|
# Flask 설정
|
|
self.flask = {
|
|
'secret_key': self._get_env('FLASK_SECRET_KEY', 'dev-secret-key'),
|
|
'host': self._get_env('FLASK_HOST', '0.0.0.0'),
|
|
'port': self._get_int('FLASK_PORT', 5000),
|
|
}
|
|
|
|
def get(self, key: str, default: Any = None) -> Any:
|
|
"""
|
|
설정값 조회 (딕셔너리 스타일)
|
|
|
|
Args:
|
|
key: 설정 키 (점 표기법 지원, 예: 'database.host')
|
|
default: 기본값
|
|
|
|
Returns:
|
|
설정값
|
|
"""
|
|
keys = key.split('.')
|
|
value = self
|
|
for k in keys:
|
|
if hasattr(value, k):
|
|
value = getattr(value, k)
|
|
elif isinstance(value, dict) and k in value:
|
|
value = value[k]
|
|
else:
|
|
return default
|
|
return value
|
|
|
|
|
|
# 싱글톤 인스턴스
|
|
_config_instance: Optional[Config] = None
|
|
|
|
|
|
@lru_cache(maxsize=1)
|
|
def get_config() -> Config:
|
|
"""
|
|
설정 싱글톤 인스턴스 반환
|
|
|
|
처음 호출 시 Config 인스턴스를 생성하고 캐시합니다.
|
|
이후 호출에서는 캐시된 인스턴스를 반환합니다.
|
|
|
|
Returns:
|
|
Config 인스턴스
|
|
"""
|
|
return Config()
|
|
|
|
|
|
def reload_config() -> Config:
|
|
"""
|
|
설정 다시 로드 (캐시 무효화)
|
|
|
|
환경변수가 변경된 후 설정을 다시 로드할 때 사용합니다.
|
|
|
|
Returns:
|
|
새로운 Config 인스턴스
|
|
"""
|
|
get_config.cache_clear()
|
|
return get_config()
|