Reviewer concerns: 1. POST /api/proxy/restart only saved config (reload), did not restart the listener. Now it touches data/restart.signal; proxy watcher polls that file separately and force-restarts the listener even when config is unchanged. 2. Editing proxy.listen_port via UI could break Docker port mapping (compose publishes 25565:25565 only). UI now shows it read-only; README documents how to change it together with compose. - proxy/main.py: ProxyState.check_restart_signal() + watcher uses it - api/config_io.py: touch_restart_signal() helper - api/routes/status.py: /api/proxy/restart -> touch_restart_signal() - frontend Settings: disabled listen_port input + 프록시 재시작 button - README + .gitignore updated
60 lines
1.9 KiB
Python
60 lines
1.9 KiB
Python
"""API 측 config IO 헬퍼.
|
|
|
|
프록시와 동일한 파일을 가리키고, atomic rename 으로 갱신해서 프록시가
|
|
mtime polling 으로 안전하게 hot reload 할 수 있게 한다.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import os
|
|
import threading
|
|
import time
|
|
from pathlib import Path
|
|
|
|
CONFIG_PATH = Path(os.environ.get("MC_CONFIG_PATH", "/data/config.json"))
|
|
LOG_DB = Path(os.environ.get("MC_LOG_DB", "/data/logs.db"))
|
|
RESTART_SIGNAL = Path(os.environ.get("MC_RESTART_SIGNAL", "/data/restart.signal"))
|
|
|
|
DEFAULT_CONFIG = {
|
|
"proxy": {"listen_port": 25565, "enabled": True},
|
|
"backend": {"host": "127.0.0.1", "port": 25565},
|
|
"allowed_domains": [
|
|
{"domain": "mc.tkrmagid.kr", "enabled": True, "note": "메인 도메인"}
|
|
],
|
|
}
|
|
|
|
_lock = threading.Lock()
|
|
|
|
|
|
def load_config() -> dict:
|
|
if not CONFIG_PATH.exists():
|
|
CONFIG_PATH.parent.mkdir(parents=True, exist_ok=True)
|
|
save_config(DEFAULT_CONFIG)
|
|
return json.loads(json.dumps(DEFAULT_CONFIG))
|
|
with _lock:
|
|
with CONFIG_PATH.open("r", encoding="utf-8") as f:
|
|
return json.load(f)
|
|
|
|
|
|
def save_config(cfg: dict) -> None:
|
|
CONFIG_PATH.parent.mkdir(parents=True, exist_ok=True)
|
|
tmp = CONFIG_PATH.with_suffix(".json.tmp")
|
|
with _lock:
|
|
with tmp.open("w", encoding="utf-8") as f:
|
|
json.dump(cfg, f, ensure_ascii=False, indent=2)
|
|
os.replace(tmp, CONFIG_PATH)
|
|
|
|
|
|
def touch_restart_signal() -> float:
|
|
"""프록시에 강제 listener restart 를 요청하는 신호 파일 갱신.
|
|
|
|
config 가 바뀌지 않은 상태에서도 listener 를 stop→start 시키고 싶을 때 사용.
|
|
"""
|
|
RESTART_SIGNAL.parent.mkdir(parents=True, exist_ok=True)
|
|
ts = time.time()
|
|
with _lock:
|
|
# touch: 파일이 없으면 만들고, 있으면 mtime 만 갱신
|
|
RESTART_SIGNAL.touch(exist_ok=True)
|
|
os.utime(RESTART_SIGNAL, (ts, ts))
|
|
return ts
|