mirror of
https://github.com/AstrBotDevs/AstrBot
synced 2026-07-16 01:40:15 +08:00
- Introduce 'astrbot bk' command with GPG signing, encryption, and digest support - Add import/export functionality using core backup modules - Refactor path management to use 'AstrbotPaths' singleton across CLI commands - Replace blocking subprocess calls with asyncio.create_subprocess_exec in backup command - Add comprehensive tests for uninstall and backup commands - Improve module resource handling for bundled dashboard assets
117 lines
3.8 KiB
Python
117 lines
3.8 KiB
Python
import asyncio
|
||
import platform
|
||
import shutil
|
||
import subprocess
|
||
from pathlib import Path
|
||
|
||
import click
|
||
from filelock import FileLock, Timeout
|
||
|
||
from astrbot.core.utils.astrbot_path import astrbot_paths
|
||
|
||
from ..utils import check_dashboard
|
||
|
||
SYSTEMD_SERVICE = r"""
|
||
# user service
|
||
[Unit]
|
||
Description=AstrBot Service
|
||
Documentation=https://github.com/AstrBotDevs/AstrBot
|
||
After=network-online.target
|
||
Wants=network-online.target
|
||
|
||
[Service]
|
||
Type=simple
|
||
WorkingDirectory=%h/.local/share/astrbot
|
||
ExecStart=/usr/bin/sh -c '/usr/bin/astrbot run || { /usr/bin/astrbot init && /usr/bin/astrbot run; }'
|
||
Restart=on-failure
|
||
RestartSec=5
|
||
StandardOutput=journal
|
||
StandardError=journal
|
||
SyslogIdentifier=astrbot-%u
|
||
Environment=PYTHONUNBUFFERED=1
|
||
|
||
[Install]
|
||
WantedBy=default.target
|
||
"""
|
||
|
||
|
||
async def initialize_astrbot(astrbot_root: Path, *, yes: bool) -> None:
|
||
"""Execute AstrBot initialization logic"""
|
||
dot_astrbot = astrbot_root / ".astrbot"
|
||
|
||
if not dot_astrbot.exists():
|
||
if yes or click.confirm(
|
||
f"Install AstrBot to this directory? {astrbot_root}",
|
||
default=True,
|
||
abort=True,
|
||
):
|
||
dot_astrbot.touch()
|
||
click.echo(f"Created {dot_astrbot}")
|
||
|
||
paths = {
|
||
"data": astrbot_root / "data",
|
||
"config": astrbot_root / "data" / "config",
|
||
"plugins": astrbot_root / "data" / "plugins",
|
||
"temp": astrbot_root / "data" / "temp",
|
||
}
|
||
|
||
for name, path in paths.items():
|
||
path.mkdir(parents=True, exist_ok=True)
|
||
click.echo(
|
||
f"{'Created' if not path.exists() else f'{name} Directory exists'}: {path}"
|
||
)
|
||
if yes or click.confirm(
|
||
"是否需要集成式 WebUI?(个人电脑推荐,服务器不推荐)",
|
||
default=True,
|
||
):
|
||
await check_dashboard(astrbot_root)
|
||
else:
|
||
click.echo("你可以使用在线面版(v4.14.4+),填写后端地址的方式来控制。")
|
||
|
||
|
||
@click.command()
|
||
@click.option("--yes", "-y", is_flag=True, help="Skip confirmation prompts")
|
||
def init(yes: bool) -> None:
|
||
"""Initialize AstrBot"""
|
||
click.echo("Initializing AstrBot...")
|
||
|
||
# 检查当前系统是否为 Linux 且存在 systemd
|
||
if platform.system() == "Linux" and shutil.which("systemctl"):
|
||
if yes or click.confirm(
|
||
"Detected Linux with systemd. Install AstrBot user service?", default=True
|
||
):
|
||
user_config_dir = Path.home() / ".config" / "systemd" / "user"
|
||
user_config_dir.mkdir(parents=True, exist_ok=True)
|
||
|
||
service_path = user_config_dir / "astrbot.service"
|
||
|
||
service_path.write_text(SYSTEMD_SERVICE)
|
||
click.echo(f"Created service file at {service_path}")
|
||
|
||
try:
|
||
subprocess.run(["systemctl", "--user", "daemon-reload"], check=True)
|
||
click.echo("Systemd daemon reloaded.")
|
||
click.echo("Management commands:")
|
||
click.echo(" Start: systemctl --user start astrbot")
|
||
click.echo(" Stop: systemctl --user stop astrbot")
|
||
click.echo(" Enable: systemctl --user enable astrbot")
|
||
click.echo(" Log: journalctl --user -u astrbot -f")
|
||
except subprocess.CalledProcessError as e:
|
||
click.echo(f"Failed to reload systemd daemon: {e}", err=True)
|
||
|
||
astrbot_root = astrbot_paths.root
|
||
lock_file = astrbot_root / "astrbot.lock"
|
||
lock = FileLock(lock_file, timeout=5)
|
||
|
||
try:
|
||
with lock.acquire():
|
||
asyncio.run(initialize_astrbot(astrbot_root, yes=yes))
|
||
click.echo("Done! You can now run 'astrbot run' to start AstrBot")
|
||
except Timeout:
|
||
raise click.ClickException(
|
||
"Cannot acquire lock file. Please check if another instance is running"
|
||
)
|
||
|
||
except Exception as e:
|
||
raise click.ClickException(f"Initialization failed: {e!s}")
|