11import asyncio
2+ import platform
3+ import shutil
4+ import subprocess
25from pathlib import Path
36
47import click
58from filelock import FileLock , Timeout
69
710from ..utils import check_dashboard , get_astrbot_root
811
12+ SYSTEMD_SERVICE = r"""
13+ # user service
14+ [Unit]
15+ Description=AstrBot Service
16+ Documentation=https://github.com/AstrBotDevs/AstrBot
17+ After=network-online.target
18+ Wants=network-online.target
919
10- async def initialize_astrbot (astrbot_root : Path ) -> None :
20+ [Service]
21+ Type=simple
22+ WorkingDirectory=%h/.local/share/astrbot
23+ ExecStart=/usr/bin/sh -c '/usr/bin/astrbot run || { /usr/bin/astrbot init && /usr/bin/astrbot run; }'
24+ Restart=on-failure
25+ RestartSec=5
26+ StandardOutput=journal
27+ StandardError=journal
28+ SyslogIdentifier=astrbot-%u
29+ Environment=PYTHONUNBUFFERED=1
30+
31+ [Install]
32+ WantedBy=default.target
33+ """
34+
35+
36+ async def initialize_astrbot (astrbot_root : Path , * , yes : bool ) -> None :
1137 """Execute AstrBot initialization logic"""
1238 dot_astrbot = astrbot_root / ".astrbot"
1339
1440 if not dot_astrbot .exists ():
15- if click .confirm (
41+ if yes or click .confirm (
1642 f"Install AstrBot to this directory? { astrbot_root } " ,
1743 default = True ,
1844 abort = True ,
@@ -29,8 +55,10 @@ async def initialize_astrbot(astrbot_root: Path) -> None:
2955
3056 for name , path in paths .items ():
3157 path .mkdir (parents = True , exist_ok = True )
32- click .echo (f"{ 'Created' if not path .exists () else 'Directory exists' } : { path } " )
33- if click .confirm (
58+ click .echo (
59+ f"{ 'Created' if not path .exists () else f'{ name } Directory exists' } : { path } "
60+ )
61+ if yes or click .confirm (
3462 "是否需要集成式 WebUI?(个人电脑推荐,服务器不推荐)" ,
3563 default = True ,
3664 ):
@@ -40,16 +68,42 @@ async def initialize_astrbot(astrbot_root: Path) -> None:
4068
4169
4270@click .command ()
43- def init () -> None :
71+ @click .option ("--yes" , "-y" , is_flag = True , help = "Skip confirmation prompts" )
72+ def init (yes : bool ) -> None :
4473 """Initialize AstrBot"""
4574 click .echo ("Initializing AstrBot..." )
75+
76+ # 检查当前系统是否为 Linux 且存在 systemd
77+ if platform .system () == "Linux" and shutil .which ("systemctl" ):
78+ if yes or click .confirm (
79+ "Detected Linux with systemd. Install AstrBot user service?" , default = True
80+ ):
81+ user_config_dir = Path .home () / ".config" / "systemd" / "user"
82+ user_config_dir .mkdir (parents = True , exist_ok = True )
83+
84+ service_path = user_config_dir / "astrbot.service"
85+
86+ service_path .write_text (SYSTEMD_SERVICE )
87+ click .echo (f"Created service file at { service_path } " )
88+
89+ try :
90+ subprocess .run (["systemctl" , "--user" , "daemon-reload" ], check = True )
91+ click .echo ("Systemd daemon reloaded." )
92+ click .echo ("Management commands:" )
93+ click .echo (" Start: systemctl --user start astrbot" )
94+ click .echo (" Stop: systemctl --user stop astrbot" )
95+ click .echo (" Enable: systemctl --user enable astrbot" )
96+ click .echo (" Log: journalctl --user -u astrbot -f" )
97+ except subprocess .CalledProcessError as e :
98+ click .echo (f"Failed to reload systemd daemon: { e } " , err = True )
99+
46100 astrbot_root = get_astrbot_root ()
47101 lock_file = astrbot_root / "astrbot.lock"
48102 lock = FileLock (lock_file , timeout = 5 )
49103
50104 try :
51105 with lock .acquire ():
52- asyncio .run (initialize_astrbot (astrbot_root ))
106+ asyncio .run (initialize_astrbot (astrbot_root , yes = yes ))
53107 click .echo ("Done! You can now run 'astrbot run' to start AstrBot" )
54108 except Timeout :
55109 raise click .ClickException (
0 commit comments