This commit is contained in:
2025-08-28 15:22:41 +08:00
parent 6a9d697f6e
commit 77729f0328
3 changed files with 72 additions and 52 deletions
+1 -1
View File
@@ -7,7 +7,7 @@ plugins {
} }
group = "xyz.thewhitedog9487" group = "xyz.thewhitedog9487"
version = "0.5.0" version = "0.5.1"
java { java {
toolchain { toolchain {
@@ -23,7 +23,7 @@ class OpenAPIConfiguration {
.contact(new Contact() .contact(new Contact()
.name("TheWhiteDog9487") .name("TheWhiteDog9487")
.url("https://www.github.com/TheWhiteDog9487/WebAPI")) .url("https://www.github.com/TheWhiteDog9487/WebAPI"))
.version("0.5.0") .version("0.5.1")
.license(new License() .license(new License()
.name("WTFPL") .name("WTFPL")
.url("https://spdx.org/licenses/WTFPL")) ) .url("https://spdx.org/licenses/WTFPL")) )
@@ -1,6 +1,9 @@
package xyz.thewhitedog9487.WebAPI.Startup; package xyz.thewhitedog9487.WebAPI.Startup;
import discord4j.core.GatewayDiscordClient;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner; import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -8,6 +11,7 @@ import java.lang.reflect.InvocationTargetException;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Arrays;
import java.util.List; import java.util.List;
@Slf4j @Slf4j
@@ -24,11 +28,13 @@ class SystemdInstallerManager implements CommandLineRunner {
ExecStart=%s ExecStart=%s
Restart=always Restart=always
Type=simple Type=simple
Environment="%s"
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target
"""; """;
@Autowired ObjectProvider<GatewayDiscordClient> DiscordClientProvider;
String CurrentOS = System.getProperty("os.name"); String CurrentOS = System.getProperty("os.name");
String CurrentUser = System.getProperty("user.name"); String CurrentUser = System.getProperty("user.name");
Path CurrentExecutableFilePath = GetExecutblePath(); Path CurrentExecutableFilePath = GetExecutblePath();
@@ -86,55 +92,67 @@ class SystemdInstallerManager implements CommandLineRunner {
public void run(String... args) throws Exception { public void run(String... args) throws Exception {
for (String Argument : args) { for (String Argument : args) {
if ( List.of("install", "--install").contains(Argument) == true ) { if ( List.of("install", "--install").contains(Argument) == true ) {
/* /*
在Native Image / Jar文件旁边生成指向自身的,名为Current的软连接 在Native Image / Jar文件旁边生成指向自身的,名为Current的软连接
然后在软连接旁生成systemd服务文件,执行目标指向软连接 然后在软连接旁生成systemd服务文件,执行目标指向软连接
*/ */
log.info("开始安装systemd服务"); List<String> DiscordBotToken = Arrays.stream(args)
log.debug("SystemProperties.os.name: {}", CurrentOS); .filter(s -> {
if ( CurrentOS.startsWith("Linux") ) { for (String o : List.of("--Discord_Bot_Token=")) {
log.debug("SystemProperties.user.name: {}", CurrentUser); if (s.startsWith(o) == true) { return true; } }
if (CurrentUser.equals("root") == false) { return false; } )
log.error("只有root才有权在系统层级安装systemd服务,但是JVM报告的当前用户是{}", CurrentUser); .toList();
throw new IllegalStateException("请使用root用户运行此命令以安装为systemd服务"); } if ( DiscordBotToken.isEmpty() == true ) {
log.debug("CurrentExecutableFilePath: {}", CurrentExecutableFilePath); log.error("必须通过\"--Discord_Bot_Token=\"参数提供Discord机器人的令牌以使本程序正常工作。");
log.debug("WorkingDirectory: {}", WorkingDirectory); throw new IllegalArgumentException("缺少必须的--Discord_Bot_Token参数"); }
log.debug("SymbolicLinkPath: {}", SymbolicLinkPath); log.info("开始安装systemd服务");
Files.deleteIfExists(SymbolicLinkPath); log.debug("SystemProperties.os.name: {}", CurrentOS);
Files.createSymbolicLink(SymbolicLinkPath, CurrentExecutableFilePath); if ( CurrentOS.startsWith("Linux") ) {
log.info("成功创建指向当前程序的软链接: {} -> {}", SymbolicLinkPath, CurrentExecutableFilePath); log.debug("SystemProperties.user.name: {}", CurrentUser);
Path CurrentJavaPath = null; if (CurrentUser.equals("root") == false) {
var IsImageCode = IsImageCode(); log.error("只有root才有权在系统层级安装systemd服务,但是JVM报告的当前用户是{}", CurrentUser);
if ( IsImageCode == false ) { throw new IllegalStateException("请使用root用户运行此命令以安装为systemd服务"); }
CurrentJavaPath = Path.of("/proc/self/exe").toRealPath(); log.debug("CurrentExecutableFilePath: {}", CurrentExecutableFilePath);
log.debug("CurrentJavaPath: {}", CurrentJavaPath); } log.debug("WorkingDirectory: {}", WorkingDirectory);
var ExecCommand = (IsImageCode == true) ? log.debug("SymbolicLinkPath: {}", SymbolicLinkPath);
SymbolicLinkPath.toString() : Files.deleteIfExists(SymbolicLinkPath);
CurrentJavaPath + " -jar " + SymbolicLinkPath.toString(); Files.createSymbolicLink(SymbolicLinkPath, CurrentExecutableFilePath);
log.debug("ExecCommand: {}", ExecCommand); log.info("成功创建指向当前程序的软链接: {} -> {}", SymbolicLinkPath, CurrentExecutableFilePath);
var ServiceFileContent = String.format( Path CurrentJavaPath = null;
TemplateContent, var IsImageCode = IsImageCode();
CurrentUser, if ( IsImageCode == false ) {
WorkingDirectory, CurrentJavaPath = Path.of("/proc/self/exe").toRealPath();
ExecCommand); log.debug("CurrentJavaPath: {}", CurrentJavaPath); }
log.debug("ServiceFileContent: \n{}", ServiceFileContent); var ExecCommand = (IsImageCode == true) ?
Files.deleteIfExists( WorkingDirectory.resolve(ServiceFileName) ); SymbolicLinkPath.toString() :
Files.writeString(WorkingDirectory.resolve(ServiceFileName), ServiceFileContent); CurrentJavaPath + " -jar " + SymbolicLinkPath.toString();
log.info("成功创建systemd服务文件: {}", WorkingDirectory.resolve(ServiceFileName)); log.debug("ExecCommand: {}", ExecCommand);
Files.deleteIfExists( ServiceFileDirectory.resolve(ServiceFileName) ); var ServiceFileContent = String.format(
Files.createSymbolicLink(ServiceFileDirectory.resolve(ServiceFileName), WorkingDirectory.resolve(ServiceFileName)); TemplateContent,
log.info("成功创建指向服务文件的软链接: {} -> {}", ServiceFileDirectory.resolve(ServiceFileName), WorkingDirectory.resolve(ServiceFileName)); CurrentUser,
new ProcessBuilder("systemctl", "daemon-reload").start().waitFor(); WorkingDirectory,
log.info("已完成systemd守护进程重载"); ExecCommand,
new ProcessBuilder("systemctl", "enable", ServiceFileName.toString()).start().waitFor(); DiscordBotToken
log.info("已启用systemd服务: {}", ServiceFileName); .getFirst()
new ProcessBuilder("systemctl", "start", ServiceFileName.toString()).start().waitFor(); .substring("--"
log.info("已启动systemd服务: {}", ServiceFileName); } .length()));
else if ( CurrentOS.startsWith("Windows") ) { log.debug("ServiceFileContent: \n{}", ServiceFileContent);
log.error("只有Linux才能使用systemd,但是JVM报告的当前系统是{}", CurrentOS); Files.deleteIfExists( WorkingDirectory.resolve(ServiceFileName) );
throw new IllegalStateException("Windows系统不支持systemd服务管理,暂不支持在Windows上自动管理服务。"); } Files.writeString(WorkingDirectory.resolve(ServiceFileName), ServiceFileContent);
System.exit(0); log.info("成功创建systemd服务文件: {}", WorkingDirectory.resolve(ServiceFileName));
} Files.deleteIfExists( ServiceFileDirectory.resolve(ServiceFileName) );
Files.createSymbolicLink(ServiceFileDirectory.resolve(ServiceFileName), WorkingDirectory.resolve(ServiceFileName));
log.info("成功创建指向服务文件的软链接: {} -> {}", ServiceFileDirectory.resolve(ServiceFileName), WorkingDirectory.resolve(ServiceFileName));
new ProcessBuilder("systemctl", "daemon-reload").start().waitFor();
log.info("已完成systemd守护进程重载");
new ProcessBuilder("systemctl", "enable", ServiceFileName.toString()).start().waitFor();
log.info("已启用systemd服务: {}", ServiceFileName);
new ProcessBuilder("systemctl", "start", ServiceFileName.toString()).start().waitFor();
log.info("已启动systemd服务: {}", ServiceFileName); }
else if ( CurrentOS.startsWith("Windows") ) {
log.error("只有Linux才能使用systemd,但是JVM报告的当前系统是{}", CurrentOS);
throw new IllegalStateException("Windows系统不支持systemd服务管理,暂不支持在Windows上自动管理服务。"); }
System.exit(0); }
else if ( List.of("uninstall", "--uninstall").contains(Argument) == true ) { else if ( List.of("uninstall", "--uninstall").contains(Argument) == true ) {
log.info("开始卸载systemd服务"); log.info("开始卸载systemd服务");
log.debug("SystemProperties.os.name: {}", CurrentOS); log.debug("SystemProperties.os.name: {}", CurrentOS);
@@ -157,4 +175,6 @@ class SystemdInstallerManager implements CommandLineRunner {
log.info("成功删除指向程序自身的软链接: {}", SymbolicLinkPath); log.info("成功删除指向程序自身的软链接: {}", SymbolicLinkPath);
new ProcessBuilder("systemctl", "daemon-reload").start().waitFor(); new ProcessBuilder("systemctl", "daemon-reload").start().waitFor();
log.info("已完成systemd守护进程重载"); } log.info("已完成systemd守护进程重载"); }
System.exit(0); } } } } System.exit(0); } }
// ↓ 并不是安装或卸载服务,于是继续正常的启动程序,让Discord客户端连接服务器,校验API密钥是否正确并确保密钥非空
DiscordClientProvider.getIfAvailable(); } }