From c93837a7a9fb72aafad26ae1511505ccfd953bdd Mon Sep 17 00:00:00 2001 From: octopus_yan Date: Thu, 12 Sep 2024 22:04:25 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=B8=BB=E7=95=8C=E9=9D=A2=E5=90=AF?= =?UTF-8?q?=E5=8A=A8=E6=8C=89=E9=92=AE=E3=80=81=E5=91=BD=E4=BB=A4=E6=89=A7?= =?UTF-8?q?=E8=A1=8C=E5=B7=A5=E5=85=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/octopusyan/alistgui/Application.java | 3 + .../octopusyan/alistgui/config/Constants.java | 4 +- .../alistgui/controller/MainController.java | 41 ++++++++- .../alistgui/manager/AListManager.java | 85 +++++++++++++++++ .../alistgui/util/ProcessesUtil.java | 91 ++++++++++++------- src/main/resources/css/main-view.scss | 21 +---- src/main/resources/fxml/main-view.fxml | 10 +- .../resources/language/language.properties | 5 + .../resources/language/language_en.properties | 5 + .../language/language_zh_CN.properties | 5 + 10 files changed, 217 insertions(+), 53 deletions(-) create mode 100644 src/main/java/cn/octopusyan/alistgui/manager/AListManager.java diff --git a/src/main/java/cn/octopusyan/alistgui/Application.java b/src/main/java/cn/octopusyan/alistgui/Application.java index a18c141..8b5afc6 100644 --- a/src/main/java/cn/octopusyan/alistgui/Application.java +++ b/src/main/java/cn/octopusyan/alistgui/Application.java @@ -6,6 +6,7 @@ import cn.octopusyan.alistgui.manager.ConfigManager; import cn.octopusyan.alistgui.manager.http.HttpConfig; import cn.octopusyan.alistgui.manager.http.HttpUtil; import cn.octopusyan.alistgui.manager.thread.ThreadPoolManager; +import cn.octopusyan.alistgui.util.ProcessesUtil; import cn.octopusyan.alistgui.util.alert.AlertUtil; import javafx.application.Platform; import javafx.scene.Scene; @@ -92,6 +93,8 @@ public class Application extends javafx.application.Application { @Override public void stop() { logger.info("application stop ..."); + // 关闭所有命令 + ProcessesUtil.destroyAll(); // 保存应用数据 ConfigManager.save(); // 停止所有线程 diff --git a/src/main/java/cn/octopusyan/alistgui/config/Constants.java b/src/main/java/cn/octopusyan/alistgui/config/Constants.java index 245eb4c..36cc886 100644 --- a/src/main/java/cn/octopusyan/alistgui/config/Constants.java +++ b/src/main/java/cn/octopusyan/alistgui/config/Constants.java @@ -14,10 +14,12 @@ public class Constants { public static final String APP_TITLE = PropertiesUtils.getInstance().getProperty("app.title"); public static final String APP_NAME = PropertiesUtils.getInstance().getProperty("app.name"); public static final String APP_VERSION = PropertiesUtils.getInstance().getProperty("app.version"); + public static final String DATA_DIR_PATH = Paths.get(".").toFile().getAbsolutePath(); public static final String BIN_DIR_PATH = STR."\{DATA_DIR_PATH}\{File.separator}bin"; - public static final String UPGRADE_PATH = STR."\{BIN_DIR_PATH}\{File.separator}upgrade.yaml"; public static final String TMP_DIR_PATH = System.getProperty("java.io.tmpdir") + APP_NAME; + + public static final String ALIST_FILE = STR."\{BIN_DIR_PATH}\{File.separator}alist.exe"; public static final String CONFIG_DIR_PATH = STR."\{DATA_DIR_PATH}\{File.separator}config"; public static final String GUI_CONFIG_PATH = STR."\{CONFIG_DIR_PATH}\{File.separator}gui.yaml"; public static final String BAK_FILE_PATH = STR."\{Constants.TMP_DIR_PATH}\{File.separator}bak"; diff --git a/src/main/java/cn/octopusyan/alistgui/controller/MainController.java b/src/main/java/cn/octopusyan/alistgui/controller/MainController.java index 5513d27..9be02b9 100644 --- a/src/main/java/cn/octopusyan/alistgui/controller/MainController.java +++ b/src/main/java/cn/octopusyan/alistgui/controller/MainController.java @@ -1,8 +1,12 @@ package cn.octopusyan.alistgui.controller; import cn.octopusyan.alistgui.base.BaseController; +import cn.octopusyan.alistgui.config.Context; +import cn.octopusyan.alistgui.manager.AListManager; import cn.octopusyan.alistgui.manager.ConsoleLog; +import javafx.application.Platform; import javafx.fxml.FXML; +import javafx.scene.control.Button; import javafx.scene.control.ScrollPane; import javafx.scene.layout.VBox; import org.slf4j.Logger; @@ -22,6 +26,10 @@ public class MainController extends BaseController { public VBox logArea; @FXML public ScrollPane logAreaSp; + @FXML + public Button statusLabel; + @FXML + public Button startButton; @Override public VBox getRootPanel() { @@ -35,11 +43,42 @@ public class MainController extends BaseController { @Override public void initViewStyle() { - + AListManager.runningProperty().addListener(_ -> setStartButton(AListManager.isRunning())); } @Override public void initViewAction() { + AListManager.runningProperty().addListener((_, _, running) -> setStartButton(running)); + } + private void setStartButton(boolean running) { + String removeStyle = running ? "success" : "danger"; + String addStyle = running ? "danger" : "success"; + String button = Context.getLanguageBinding(STR."main.control.\{running ? "stop" : "start"}").get(); + String status = Context.getLanguageBinding(STR."main.status.label-\{running ? "running" : "stop"}").get(); + + Platform.runLater(() -> { + startButton.getStyleClass().remove(removeStyle); + startButton.getStyleClass().add(addStyle); + startButton.textProperty().set(button); + + statusLabel.getStyleClass().remove(addStyle); + statusLabel.getStyleClass().add(removeStyle); + statusLabel.textProperty().set(status); + }); + } + + @FXML + public void start() { + if (AListManager.isRunning()) { + AListManager.stop(); + } else { + AListManager.start(); + } + } + + @FXML + public void restart() { + AListManager.restart(); } } diff --git a/src/main/java/cn/octopusyan/alistgui/manager/AListManager.java b/src/main/java/cn/octopusyan/alistgui/manager/AListManager.java new file mode 100644 index 0000000..6b9c91f --- /dev/null +++ b/src/main/java/cn/octopusyan/alistgui/manager/AListManager.java @@ -0,0 +1,85 @@ +package cn.octopusyan.alistgui.manager; + +import cn.octopusyan.alistgui.config.Constants; +import cn.octopusyan.alistgui.config.Context; +import cn.octopusyan.alistgui.util.ProcessesUtil; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.value.ChangeListener; + +/** + * AList 管理 + * + * @author octopus_yan + */ +public class AListManager { + public static final String START_COMMAND = STR."\{Constants.ALIST_FILE} server"; + private static final ProcessesUtil util; + private static final BooleanProperty running = new SimpleBooleanProperty(false); + + static { + util = ProcessesUtil.init(Constants.BIN_DIR_PATH); + } + + public static BooleanProperty runningProperty() { + return running; + } + + public static boolean isRunning() { + return running.get(); + } + + public static void start() { + ConsoleLog.info(getText("alist.status.start")); + if (running.get()) { + ConsoleLog.warning(getText("alist.status.start.running")); + return; + } + + running.set(true); + util.exec(START_COMMAND, new ProcessesUtil.OnExecuteListener() { + @Override + public void onExecute(String msg) { + if (ConsoleLog.isInit()) + ConsoleLog.msg(msg); + } + + @Override + public void onExecuteSuccess(int exitValue) { + running.set(false); + } + + @Override + public void onExecuteError(Exception e) { + running.set(false); + } + }); + } + + public static void stop() { + ConsoleLog.info(getText("alist.status.stop")); + if (!running.get()) { + ConsoleLog.warning(getText("alist.status.stop.stopped")); + return; + } + util.destroy(); + } + + static ChangeListener changeListener; + + public static void restart() { + stop(); + changeListener = (_, _, run) -> { + if (run) return; + start(); + if (changeListener != null) { + running.removeListener(changeListener); + } + }; + running.addListener(changeListener); + } + + private static String getText(String code) { + return Context.getLanguageBinding(code).get(); + } +} diff --git a/src/main/java/cn/octopusyan/alistgui/util/ProcessesUtil.java b/src/main/java/cn/octopusyan/alistgui/util/ProcessesUtil.java index 0cd12bf..6c1e586 100644 --- a/src/main/java/cn/octopusyan/alistgui/util/ProcessesUtil.java +++ b/src/main/java/cn/octopusyan/alistgui/util/ProcessesUtil.java @@ -1,44 +1,66 @@ package cn.octopusyan.alistgui.util; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.exec.*; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import java.io.File; import java.io.IOException; +import java.util.HashSet; +import java.util.Set; /** * 命令工具类 * * @author octopus_yan@foxmail.com */ +@Slf4j public class ProcessesUtil { - - private static final Logger logger = LoggerFactory.getLogger(ProcessesUtil.class); private static final String NEW_LINE = System.lineSeparator(); - private static final DefaultExecuteResultHandler handler = new DefaultExecuteResultHandler(); - public static boolean exec(String command) { - try { - exec(command, msg -> {}); - handler.waitFor(); - } catch (Exception e) { - logger.error("", e); + private final Executor executor = DefaultExecutor.builder().get(); + private final ShutdownHookProcessDestroyer processDestroyer; + private DefaultExecuteResultHandler handler; + private final PumpStreamHandler streamHandler; + private OnExecuteListener listener; + private CommandLine commandLine; + private final LogOutputStream logout = new LogOutputStream() { + @Override + protected void processLine(String line, int logLevel) { + if (listener != null) + listener.onExecute(line + NEW_LINE); } - return 0 == handler.getExitValue(); + }; + + private static final Set set = new HashSet<>(); + + /** + * Prevent construction. + */ + private ProcessesUtil(String workingDirectory) { + streamHandler = new PumpStreamHandler(logout, logout); + executor.setStreamHandler(streamHandler); + executor.setWorkingDirectory(new File(workingDirectory)); + executor.setExitValue(1); + processDestroyer = new ShutdownHookProcessDestroyer(); + executor.setProcessDestroyer(processDestroyer); } - public static void exec(String command, OnExecuteListener listener) { - LogOutputStream logout = new LogOutputStream() { - @Override - protected void processLine(String line, int logLevel) { - if (listener != null) listener.onExecute(line + NEW_LINE); - } - }; + public static ProcessesUtil init(String workingDirectory) { + ProcessesUtil util = new ProcessesUtil(workingDirectory); + set.add(util); + return util; + } - CommandLine commandLine = CommandLine.parse(command); - DefaultExecutor executor = DefaultExecutor.builder().get(); - executor.setStreamHandler(new PumpStreamHandler(logout, logout)); - DefaultExecuteResultHandler handler = new DefaultExecuteResultHandler() { + public boolean exec(String command) throws IOException { + commandLine = CommandLine.parse(command); + int execute = executor.execute(commandLine); + return 0 == execute; + } + + public void exec(String command, OnExecuteListener listener) { + this.listener = listener; + commandLine = CommandLine.parse(command); + handler = new DefaultExecuteResultHandler() { @Override public void onProcessComplete(int exitValue) { if (listener != null) { @@ -60,15 +82,22 @@ public class ProcessesUtil { } } - public interface OnExecuteListener { - void onExecute(String msg); - default void onExecuteSuccess(int exitValue){} - default void onExecuteError(Exception e){} + public void destroy() { + if (processDestroyer.isEmpty()) return; + processDestroyer.run(); } - /** - * Prevent construction. - */ - private ProcessesUtil() { + public static void destroyAll() { + set.forEach(ProcessesUtil::destroy); + } + + public interface OnExecuteListener { + void onExecute(String msg); + + default void onExecuteSuccess(int exitValue) { + } + + default void onExecuteError(Exception e) { + } } } diff --git a/src/main/resources/css/main-view.scss b/src/main/resources/css/main-view.scss index a919991..e23de78 100644 --- a/src/main/resources/css/main-view.scss +++ b/src/main/resources/css/main-view.scss @@ -12,10 +12,6 @@ -fx-background-radius: 10; -fx-text-alignment: CENTER; -fx-border-radius: 10; - -color-button-bg: -color-success-3; - -color-button-border: -color-button-bg; - -color-button-border-hover: -color-button-bg; - -color-button-bg-hover: -color-button-bg; } .control-menu, #startButton, #passwordButton, #restartButton, #moreButton { @@ -27,12 +23,6 @@ } #startButton { - -color-button-bg: -color-danger-4; - -color-button-bg-hover: -color-button-bg; - -color-button-bg-focused: -color-button-bg; - -color-button-bg-pressed: -color-button-bg; - -color-button-border: -color-button-bg; - -color-button-border-hover: -color-button-bg; -fx-border-color: -color-button-bg; } @@ -41,8 +31,6 @@ -color-button-bg-hover: -color-button-bg; -color-button-bg-focused: -color-button-bg; -color-button-bg-pressed: -color-button-bg; - -color-button-border: -color-button-bg; - -color-button-border-hover: -color-button-bg; -fx-border-color: -color-button-bg; } @@ -51,15 +39,16 @@ -color-button-bg-hover: -color-button-bg; -color-button-bg-focused: -color-button-bg; -color-button-bg-pressed: -color-button-bg; - -color-button-border: -color-button-bg; - -color-button-border-hover: -color-button-bg; -fx-border-color: -color-button-bg; } #moreButton { - -fx-background-color: transparent; - -fx-text-fill: -color-chart-6; + -color-button-bg-focused: transparent; + -color-button-bg-pressed: transparent; + -color-button-bg-hover: -color-chart-6-alpha20; + -color-button-border: -color-chart-6; -fx-border-color: -color-chart-6; + -color-button-border-hover: -color-chart-6-alpha70; } .logArea { diff --git a/src/main/resources/fxml/main-view.fxml b/src/main/resources/fxml/main-view.fxml index fde4e3a..92a3036 100644 --- a/src/main/resources/fxml/main-view.fxml +++ b/src/main/resources/fxml/main-view.fxml @@ -24,10 +24,12 @@ -