仓库初始化
This commit is contained in:
@@ -0,0 +1,414 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Project configuration model."""
|
||||
|
||||
from util.runtime import *
|
||||
|
||||
def _empty_config_data():
|
||||
"""无项目时的默认配置结构,避免 get() 报错"""
|
||||
return {
|
||||
"workspace": {"server_root": "", "run_dir": ""},
|
||||
"database": {"host": "", "user": "", "password": "", "port": 3306},
|
||||
"server": {
|
||||
"prefix": "ddxq2", "login_server_node": "", "center_server_node": "",
|
||||
"default_server_id": "1", "server_type": "game_server", "server_name": "",
|
||||
"ip": get_local_ip(), "game_host": get_local_ip(), "cookie": "ddxq2-node",
|
||||
},
|
||||
"erlang": {"r25_path": "", "erl": "erl", "werl": "werl", "escript": "escript"},
|
||||
"login_db": {
|
||||
"name": "", "server_id": 900, "host": "", "port": 0,
|
||||
"user": "", "password": "",
|
||||
},
|
||||
"commands": {"rebar": REBAR3_CMD, "svn": "svn"},
|
||||
"terminal": {"launch_mode": "auto", "exe_path": ""},
|
||||
}
|
||||
|
||||
|
||||
class Config:
|
||||
"""项目配置管理类:读写当前打开项目下的 .server_manager/config/tool.config(与项目一起走)。
|
||||
打开项目时会将软件目录下受管模板同步到 .server_manager/config,并保留项目自己的 tool.config。
|
||||
支持“无项目”启动:project_root=None 时仅显示欢迎页;通过 open_project(path) 打开项目后加载该项目配置。
|
||||
"""
|
||||
|
||||
def __init__(self, project_root: Optional[Path] = None):
|
||||
if getattr(sys, 'frozen', False):
|
||||
self._exe_dir = Path(sys.executable).parent
|
||||
self._script_dir = self._exe_dir
|
||||
else:
|
||||
self._script_dir = SRC_DIR
|
||||
self._exe_dir = self._script_dir.parent.parent
|
||||
|
||||
self.tool_dir = None
|
||||
self.tool_config_path = None
|
||||
self.config_error = None
|
||||
self.data = _empty_config_data()
|
||||
|
||||
if project_root is not None:
|
||||
self.open_project(Path(project_root))
|
||||
else:
|
||||
self.config_error = "未打开项目"
|
||||
|
||||
def has_project(self) -> bool:
|
||||
"""是否已打开有效项目(存在 .server_manager/config)"""
|
||||
if self.tool_dir is None:
|
||||
return False
|
||||
return get_server_manager_config_dir(self.tool_dir).is_dir()
|
||||
|
||||
def open_project(self, project_root: Path) -> bool:
|
||||
"""打开项目目录并同步受管配置模板到 .server_manager/config。成功返回 True。"""
|
||||
project_root = Path(project_root).resolve()
|
||||
cfg_dir, err = ensure_and_get_server_manager_config_dir(project_root)
|
||||
if not cfg_dir:
|
||||
self.config_error = err
|
||||
return False
|
||||
self.tool_dir = project_root
|
||||
self.tool_config_path = cfg_dir / "tool.config"
|
||||
self.config_error = None
|
||||
self.data = self._load_config()
|
||||
return True
|
||||
|
||||
def _find_server_root(self) -> Path:
|
||||
"""查找有效的服务器根目录
|
||||
|
||||
查找顺序:优先运行目录(当前工作目录),再考虑 exe/脚本所在位置。
|
||||
|
||||
Returns:
|
||||
有效的服务器根目录路径,如果都找不到返回 None
|
||||
"""
|
||||
candidates = [
|
||||
Path.cwd(), # 运行目录优先
|
||||
self._exe_dir,
|
||||
self._script_dir,
|
||||
]
|
||||
|
||||
for path in candidates:
|
||||
if (get_server_manager_config_dir(path) / "default.kv").exists():
|
||||
return path
|
||||
if (path / "config" / "default.kv").exists():
|
||||
return path
|
||||
|
||||
return None
|
||||
|
||||
def _load_tool_config(self) -> dict:
|
||||
"""加载 tool.config 文件"""
|
||||
if self.tool_config_path is None or not self.tool_config_path.exists():
|
||||
return {}
|
||||
|
||||
config = {}
|
||||
try:
|
||||
with open(self.tool_config_path, 'r', encoding='utf-8') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line or line.startswith('#'):
|
||||
continue
|
||||
if '=' in line:
|
||||
key, value = line.split('=', 1)
|
||||
config[key.strip()] = value.strip()
|
||||
except Exception:
|
||||
return {}
|
||||
return config
|
||||
|
||||
def _save_tool_config(self, config: dict):
|
||||
"""保存 tool.config 文件"""
|
||||
lines = [
|
||||
"# Server Manager config",
|
||||
"# 此文件配置工具运行所需的环境路径",
|
||||
"",
|
||||
"# === 工作目录配置 ===",
|
||||
f"server_root={config.get('server_root', '')}",
|
||||
f"run_dir={config.get('run_dir', '')}",
|
||||
"",
|
||||
"# === 启动窗口配置 ===",
|
||||
f"terminal_launch_mode={config.get('terminal_launch_mode', 'auto')}",
|
||||
f"terminal_exe_path={config.get('terminal_exe_path', '')}",
|
||||
"",
|
||||
"# === Erlang 配置 ===",
|
||||
f"r25_path={config.get('r25_path', '')}",
|
||||
"",
|
||||
"# === 数据库配置 ===",
|
||||
f"db_host={config.get('db_host', '')}",
|
||||
f"db_port={config.get('db_port', '3306')}",
|
||||
f"db_user={config.get('db_user', '')}",
|
||||
f"db_pass={config.get('db_pass', '')}",
|
||||
"",
|
||||
"# === 登录服数据库配置(远程连接用)===",
|
||||
f"login_db_name={config.get('login_db_name', '')}",
|
||||
f"login_db_server_id={config.get('login_db_server_id', '900')}",
|
||||
f"login_db_host={config.get('login_db_host', '')}",
|
||||
f"login_db_port={config.get('login_db_port', '0')}",
|
||||
f"login_db_user={config.get('login_db_user', '')}",
|
||||
f"login_db_pass={config.get('login_db_pass', '')}",
|
||||
"",
|
||||
"# === 服务器基础配置 ===",
|
||||
f"prefix={config.get('prefix', 'ddxq2')}",
|
||||
f"default_server_id={config.get('default_server_id', '1')}",
|
||||
f"server_type={config.get('server_type', 'game_server')}",
|
||||
f"server_name={config.get('server_name', '')}",
|
||||
f"login_node={config.get('login_node', '')}",
|
||||
f"center_node={config.get('center_node', '')}",
|
||||
f"cookie={config.get('cookie', 'ddxq2-node')}",
|
||||
]
|
||||
|
||||
self.tool_config_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
with open(self.tool_config_path, 'w', encoding='utf-8') as f:
|
||||
f.write('\n'.join(lines))
|
||||
|
||||
def _load_default_kv(self, server_root: str) -> dict:
|
||||
"""从 default.kv 读取默认配置"""
|
||||
if not server_root:
|
||||
return {}
|
||||
|
||||
default_kv_path = get_server_manager_config_dir(server_root) / 'default.kv'
|
||||
if not default_kv_path.exists():
|
||||
return {}
|
||||
|
||||
config = {}
|
||||
try:
|
||||
with open(default_kv_path, 'r', encoding='utf-8') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line or line.startswith('#'):
|
||||
continue
|
||||
if '=' in line:
|
||||
key, value = line.split('=', 1)
|
||||
config[key.strip()] = value.strip()
|
||||
except Exception:
|
||||
return {}
|
||||
return config
|
||||
|
||||
def _load_config(self):
|
||||
"""加载配置,从 tool.config 读取,空值从 default.kv 补充。
|
||||
以当前已打开的项目目录(self.tool_dir)为 server_root 默认值,tool.config 可覆盖。
|
||||
"""
|
||||
if self.tool_dir is None or self.tool_config_path is None:
|
||||
return self.data
|
||||
tool_cfg = self._load_tool_config()
|
||||
is_first_run = not self.tool_config_path.exists()
|
||||
|
||||
# 以当前项目目录为默认,tool.config 可覆盖
|
||||
server_root = tool_cfg.get('server_root', '') or str(self.tool_dir)
|
||||
run_dir = tool_cfg.get('run_dir', '')
|
||||
if not run_dir and server_root:
|
||||
run_dir = str(Path(server_root) / "run")
|
||||
|
||||
# 首次运行时,创建运行目录
|
||||
if is_first_run and run_dir:
|
||||
run_path = Path(run_dir)
|
||||
if not run_path.exists():
|
||||
try:
|
||||
run_path.mkdir(parents=True, exist_ok=True)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# 如果有 server_root,尝试从 default.kv 读取默认值
|
||||
default_kv = self._load_default_kv(server_root)
|
||||
|
||||
# 辅助函数:优先使用 tool.config 值,为空则使用 default.kv 值
|
||||
def get_value(tool_key, default_key, fallback=''):
|
||||
val = tool_cfg.get(tool_key, '')
|
||||
if not val and default_kv:
|
||||
val = default_kv.get(default_key, fallback)
|
||||
# 去掉可能的引号
|
||||
if isinstance(val, str) and val.startswith("'") and val.endswith("'"):
|
||||
val = val[1:-1]
|
||||
return val if val else fallback
|
||||
|
||||
db_host = get_value('db_host', 'db_host', '')
|
||||
db_user = get_value('db_user', 'db_user', '')
|
||||
db_pass = get_value('db_pass', 'db_pass', '')
|
||||
db_port = get_value('db_port', 'db_port', '3306')
|
||||
cookie = get_value('cookie', 'cookie', 'ddxq2-node')
|
||||
login_db_name = get_value('login_db_name', 'login_db_name', '')
|
||||
login_db_server_id = get_value('login_db_server_id', 'login_db_server_id', '900')
|
||||
login_db_host = get_value('login_db_host', 'login_db_host', '')
|
||||
login_db_port = get_value('login_db_port', 'login_db_port', '0')
|
||||
login_db_user = get_value('login_db_user', 'login_db_user', '')
|
||||
login_db_pass = get_value('login_db_pass', 'login_db_pass', '')
|
||||
r25_path = get_value('r25_path', 'r25_path', '')
|
||||
terminal_launch_mode = (tool_cfg.get('terminal_launch_mode', '') or 'auto').strip().lower()
|
||||
terminal_exe_path = tool_cfg.get('terminal_exe_path', '')
|
||||
if not terminal_exe_path:
|
||||
legacy_exe = tool_cfg.get('terminal_custom_command', '')
|
||||
legacy_cwd = tool_cfg.get('terminal_custom_cwd', '')
|
||||
if legacy_exe and legacy_cwd and not any(sep in legacy_exe for sep in ('/', '\\')):
|
||||
legacy_path = Path(os.path.expandvars(os.path.expanduser(legacy_cwd))) / legacy_exe
|
||||
if legacy_path.is_file():
|
||||
terminal_exe_path = str(legacy_path.resolve())
|
||||
if not terminal_exe_path:
|
||||
terminal_exe_path = legacy_exe
|
||||
|
||||
# 服务器基础配置
|
||||
prefix = get_value('prefix', 'prefix', 'ddxq2')
|
||||
default_server_id = get_value('default_server_id', 'server_id', '1')
|
||||
server_type = get_value('server_type', 'server_type', 'game_server')
|
||||
server_name = get_value('server_name', 'server_name', '')
|
||||
local_ip = get_local_ip()
|
||||
login_node = get_value('login_node', 'login_node', '')
|
||||
center_node = get_value('center_node', 'center_node', '')
|
||||
|
||||
config_data = {
|
||||
"workspace": {
|
||||
"server_root": server_root,
|
||||
"run_dir": run_dir,
|
||||
},
|
||||
"database": {
|
||||
"host": db_host,
|
||||
"user": db_user,
|
||||
"password": db_pass,
|
||||
"port": int(db_port) if db_port else 3306,
|
||||
},
|
||||
"server": {
|
||||
"prefix": prefix,
|
||||
"login_server_node": login_node,
|
||||
"center_server_node": center_node,
|
||||
"default_server_id": default_server_id,
|
||||
"server_type": server_type,
|
||||
"server_name": server_name,
|
||||
"ip": local_ip,
|
||||
"game_host": local_ip,
|
||||
"cookie": cookie,
|
||||
},
|
||||
"erlang": {
|
||||
"r25_path": r25_path,
|
||||
"erl": "erl",
|
||||
"werl": "werl",
|
||||
"escript": "escript"
|
||||
},
|
||||
"login_db": {
|
||||
"name": login_db_name,
|
||||
"server_id": int(login_db_server_id) if login_db_server_id else 900,
|
||||
"host": login_db_host,
|
||||
"port": int(login_db_port) if login_db_port else 0,
|
||||
"user": login_db_user,
|
||||
"password": login_db_pass,
|
||||
},
|
||||
"commands": {
|
||||
"rebar": REBAR3_CMD,
|
||||
"svn": "svn"
|
||||
},
|
||||
"terminal": {
|
||||
"launch_mode": terminal_launch_mode,
|
||||
"exe_path": terminal_exe_path,
|
||||
},
|
||||
}
|
||||
|
||||
# 每次启动都检查配置完整性,从 default.kv 补充缺失的值
|
||||
need_save = is_first_run
|
||||
if default_kv:
|
||||
# 检查是否有从 default.kv 补充的值
|
||||
fields_to_check = [
|
||||
('db_host', db_host),
|
||||
('db_user', db_user),
|
||||
('db_pass', db_pass),
|
||||
('prefix', prefix),
|
||||
('login_node', login_node),
|
||||
('center_node', center_node),
|
||||
('cookie', cookie),
|
||||
]
|
||||
for field_name, new_value in fields_to_check:
|
||||
old_value = tool_cfg.get(field_name, '')
|
||||
if not old_value and new_value:
|
||||
need_save = True
|
||||
break
|
||||
|
||||
if need_save:
|
||||
self.data = config_data
|
||||
self.save()
|
||||
|
||||
return config_data
|
||||
|
||||
def has_default_kv(self) -> bool:
|
||||
"""检查 default.kv 是否存在"""
|
||||
server_root = self.get('workspace', 'server_root', default='')
|
||||
if not server_root:
|
||||
return False
|
||||
default_kv_path = get_server_manager_config_dir(server_root) / 'default.kv'
|
||||
return default_kv_path.exists()
|
||||
|
||||
def is_config_complete(self) -> bool:
|
||||
"""检查工具配置是否完整"""
|
||||
# 检查必要的配置项
|
||||
db_host = self.get('database', 'host', default='')
|
||||
db_user = self.get('database', 'user', default='')
|
||||
prefix = self.get('server', 'prefix', default='')
|
||||
return bool(db_host and db_user and prefix)
|
||||
|
||||
def save(self):
|
||||
"""保存配置到 tool.config"""
|
||||
if self.tool_config_path is None:
|
||||
return
|
||||
local_ip = get_local_ip()
|
||||
self.set(local_ip, 'server', 'ip')
|
||||
self.set(local_ip, 'server', 'game_host')
|
||||
tool_cfg = {
|
||||
'server_root': self.get('workspace', 'server_root', default=''),
|
||||
'run_dir': self.get('workspace', 'run_dir', default=''),
|
||||
'r25_path': self.get('erlang', 'r25_path', default=''),
|
||||
'db_host': self.get('database', 'host', default=''),
|
||||
'db_port': str(self.get('database', 'port', default=3306)),
|
||||
'db_user': self.get('database', 'user', default=''),
|
||||
'db_pass': self.get('database', 'password', default=''),
|
||||
'login_db_name': self.get('login_db', 'name', default=''),
|
||||
'login_db_server_id': str(self.get('login_db', 'server_id', default=900)),
|
||||
'login_db_host': self.get('login_db', 'host', default=''),
|
||||
'login_db_port': str(self.get('login_db', 'port', default=0)),
|
||||
'login_db_user': self.get('login_db', 'user', default=''),
|
||||
'login_db_pass': self.get('login_db', 'password', default=''),
|
||||
'prefix': self.get('server', 'prefix', default='ddxq2'),
|
||||
'default_server_id': self.get('server', 'default_server_id', default='1'),
|
||||
'server_type': self.get('server', 'server_type', default='game_server'),
|
||||
'server_name': self.get('server', 'server_name', default=''),
|
||||
'login_node': self.get('server', 'login_server_node', default=''),
|
||||
'center_node': self.get('server', 'center_server_node', default=''),
|
||||
'cookie': self.get('server', 'cookie', default='ddxq2-node'),
|
||||
'terminal_launch_mode': self.get('terminal', 'launch_mode', default='auto'),
|
||||
'terminal_exe_path': self.get('terminal', 'exe_path', default=''),
|
||||
}
|
||||
self._save_tool_config(tool_cfg)
|
||||
|
||||
def get(self, *keys, default=None):
|
||||
"""获取配置项"""
|
||||
result = self.data
|
||||
for key in keys:
|
||||
if isinstance(result, dict) and key in result:
|
||||
result = result[key]
|
||||
else:
|
||||
return default
|
||||
return result
|
||||
|
||||
def set(self, value, *keys):
|
||||
"""设置配置项"""
|
||||
target = self.data
|
||||
for key in keys[:-1]:
|
||||
if key not in target:
|
||||
target[key] = {}
|
||||
target = target[key]
|
||||
target[keys[-1]] = value
|
||||
|
||||
def is_configured(self) -> bool:
|
||||
"""检查必要配置是否已设置"""
|
||||
server_root = self.get('workspace', 'server_root', default='')
|
||||
return bool(server_root and Path(server_root).exists())
|
||||
|
||||
def get_missing_config(self) -> list:
|
||||
"""获取缺失的必要配置项"""
|
||||
missing = []
|
||||
server_root = self.get('workspace', 'server_root', default='')
|
||||
if not server_root:
|
||||
missing.append("服务器根目录 (server_root)")
|
||||
elif not Path(server_root).exists():
|
||||
missing.append(f"服务器根目录不存在: {server_root}")
|
||||
return missing
|
||||
|
||||
|
||||
def apply_terminal_launch_config(config: Config) -> None:
|
||||
"""Apply project terminal launch settings to the process environment."""
|
||||
mode = (config.get('terminal', 'launch_mode', default='auto') or 'auto').strip().lower() or 'auto'
|
||||
terminal_exe = (config.get('terminal', 'exe_path', default='') or '').strip()
|
||||
|
||||
os.environ['SERVER_MANAGER_TERMINAL'] = mode
|
||||
if terminal_exe:
|
||||
os.environ['SERVER_MANAGER_TERMINAL_EXE'] = terminal_exe
|
||||
else:
|
||||
os.environ.pop('SERVER_MANAGER_TERMINAL_EXE', None)
|
||||
os.environ.pop('SERVER_MANAGER_TERMINAL_COMMAND', None)
|
||||
os.environ.pop('SERVER_MANAGER_TERMINAL_CWD', None)
|
||||
Reference in New Issue
Block a user