From 5a3522a71b357ea31116c1c421147c738b73cb26 Mon Sep 17 00:00:00 2001 From: KasumiNova <3044344887@qq.com> Date: Sun, 6 Nov 2022 23:47:11 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BD=8E=E6=80=A7=E8=83=BD=E6=A8=A1=E5=BC=8F?= =?UTF-8?q?=E6=94=B9=E5=90=8D=E4=B8=BA=E5=8D=95=E7=BA=BF=E7=A8=8B=E6=A8=A1?= =?UTF-8?q?=E5=BC=8F=EF=BC=9B=E7=BA=BF=E7=A8=8B=E6=B1=A0=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=E7=8E=B0=E5=9C=A8=E4=B8=8D=E5=86=8D=E9=9C=80=E8=A6=81=E9=87=8D?= =?UTF-8?q?=E5=90=AF=E7=94=9F=E6=95=88=EF=BC=9B=E5=B0=86=20ServerInterface?= =?UTF-8?q?=20=E5=88=86=E7=A6=BB=E5=87=BA=E9=9D=9E=20GUI=20=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E5=92=8C=20GUI=20=E6=8E=A5=E5=8F=A3=EF=BC=9B=E5=B0=86?= =?UTF-8?q?=20AbstractServer=20=E5=88=86=E7=A6=BB=E5=87=BA=E9=9D=9E=20GUI?= =?UTF-8?q?=20=E7=B1=BB=E5=92=8C=20GUI=20=E7=B1=BB=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../balloonserver/BalloonServer.java | 8 +- .../configurations/BalloonServerConfig.java | 12 +- .../configurations/ConfigurationManager.java | 2 +- .../gui/panels/SettingsPanel.java | 28 +- .../ruleeditor/RuleEditorActionListener.java | 6 +- .../servers/AbstractGUIServer.java | 262 ++++++++++++++++++ .../balloonserver/servers/AbstractServer.java | 250 +---------------- .../servers/GUIServerInterface.java | 18 ++ .../servers/ServerInterface.java | 25 +- .../servers/localserver/IntegratedServer.java | 5 +- .../IntegratedServerInterface.java | 4 +- .../RemoteIntegratedServerClient.java | 29 +- .../balloonserver/utils/GUILogger.java | 34 +-- 13 files changed, 341 insertions(+), 342 deletions(-) create mode 100644 src/main/java/github/kasuminova/balloonserver/servers/AbstractGUIServer.java create mode 100644 src/main/java/github/kasuminova/balloonserver/servers/GUIServerInterface.java diff --git a/src/main/java/github/kasuminova/balloonserver/BalloonServer.java b/src/main/java/github/kasuminova/balloonserver/BalloonServer.java index b415ec1..1d72613 100644 --- a/src/main/java/github/kasuminova/balloonserver/BalloonServer.java +++ b/src/main/java/github/kasuminova/balloonserver/BalloonServer.java @@ -155,13 +155,13 @@ private static void init() { updateSplashProgress(100, "已完成"); MAIN_FRAME.setVisible(true); - loadAutoUpdateFeature(); + startUpdateChecker(); } /** * 载入自动更新功能 */ - private static void loadAutoUpdateFeature() { + private static void startUpdateChecker() { //当前是否在检查更新,防止长时间静置未操作弹出多个对话框 AtomicBoolean isCheckingUpdate = new AtomicBoolean(false); //更新检查线程,每一小时检查一次最新版本 @@ -231,8 +231,8 @@ private static void loadServerTabbedPaneProperty() { SERVER_TABBED_PANE.putClientProperty("JTabbedPane.scrollButtonsPlacement", "both"); } - private static void initFileThreadPool() { - if (CONFIG.isLowIOPerformanceMode()) { + public static void initFileThreadPool() { + if (CONFIG.isSingleThreadMode()) { GLOBAL_FILE_THREAD_POOL.setCorePoolSize(1); GLOBAL_FILE_THREAD_POOL.setMaximumPoolSize(1); } else if (CONFIG.getFileThreadPoolSize() > 0) { diff --git a/src/main/java/github/kasuminova/balloonserver/configurations/BalloonServerConfig.java b/src/main/java/github/kasuminova/balloonserver/configurations/BalloonServerConfig.java index 369f76d..ba4aff9 100644 --- a/src/main/java/github/kasuminova/balloonserver/configurations/BalloonServerConfig.java +++ b/src/main/java/github/kasuminova/balloonserver/configurations/BalloonServerConfig.java @@ -32,10 +32,10 @@ public class BalloonServerConfig extends Configuration { @JSONField(ordinal = 5) private int closeOperation = 0; /** - * 低性能模式 + * 单线程模式 */ @JSONField(ordinal = 6) - private boolean lowIOPerformanceMode = false; + private boolean singleThreadMode = false; /** * 文件线程池大小 */ @@ -111,12 +111,12 @@ public BalloonServerConfig setAutoCheckUpdates(boolean autoCheckUpdates) { return this; } - public boolean isLowIOPerformanceMode() { - return lowIOPerformanceMode; + public boolean isSingleThreadMode() { + return singleThreadMode; } - public BalloonServerConfig setLowIOPerformanceMode(boolean lowIOPerformanceMode) { - this.lowIOPerformanceMode = lowIOPerformanceMode; + public BalloonServerConfig setSingleThreadMode(boolean singleThreadMode) { + this.singleThreadMode = singleThreadMode; return this; } diff --git a/src/main/java/github/kasuminova/balloonserver/configurations/ConfigurationManager.java b/src/main/java/github/kasuminova/balloonserver/configurations/ConfigurationManager.java index 6f7bf57..38c4307 100644 --- a/src/main/java/github/kasuminova/balloonserver/configurations/ConfigurationManager.java +++ b/src/main/java/github/kasuminova/balloonserver/configurations/ConfigurationManager.java @@ -37,7 +37,7 @@ public static void loadBalloonServerConfigFromFile(String path, BalloonServerCon .setCloseOperation(config.getCloseOperation()) .setAutoCheckUpdates(config.isAutoCheckUpdates()) .setAutoUpdate(config.isAutoUpdate()) - .setLowIOPerformanceMode(config.isLowIOPerformanceMode()) + .setSingleThreadMode(config.isSingleThreadMode()) .setFileThreadPoolSize(config.getFileThreadPoolSize()); } diff --git a/src/main/java/github/kasuminova/balloonserver/gui/panels/SettingsPanel.java b/src/main/java/github/kasuminova/balloonserver/gui/panels/SettingsPanel.java index ed4f29a..290f756 100644 --- a/src/main/java/github/kasuminova/balloonserver/gui/panels/SettingsPanel.java +++ b/src/main/java/github/kasuminova/balloonserver/gui/panels/SettingsPanel.java @@ -2,6 +2,7 @@ import cn.hutool.core.io.IORuntimeException; import com.formdev.flatlaf.intellijthemes.materialthemeuilite.*; +import github.kasuminova.balloonserver.BalloonServer; import github.kasuminova.balloonserver.configurations.BalloonServerConfig; import github.kasuminova.balloonserver.configurations.CloseOperation; import github.kasuminova.balloonserver.configurations.ConfigurationManager; @@ -30,7 +31,7 @@ public class SettingsPanel { }; private static final JComboBox CLOSE_OPERATION_COMBO_BOX = new JComboBox<>(OPERATIONS); private static final JSpinner FILE_THREAD_POOL_SIZE_SPINNER = new JSpinner(); - private static final JCheckBox LOW_IO_PERFORMANCE_MODE = new JCheckBox("低性能模式 (重启生效)"); + private static final JCheckBox SINGLE_THREAD_MODE = new JCheckBox("单线程模式"); private static final JCheckBox ENABLE_DEBUG_MODE = new JCheckBox("启用 Debug 模式"); private static final int MAXIMUM_FILE_THREAD_POOL_SIZE = 1024; public static JPanel createPanel() { @@ -70,11 +71,11 @@ public static JPanel createPanel() { JLabel closeOperationsDesc = new JLabel("此项决定点击 BalloonServer 窗口右上角关闭按钮后程序的操作."); closeOperationsDesc.setForeground(ModernColors.BLUE); - //低性能模式 - JLabel lowIOPerformanceModeDesc0 = new JLabel("此项选中后, 将会限制生成缓存的线程数至单线程, 对于机械盘等低 IO 性能的服务器可能会有性能提升."); - lowIOPerformanceModeDesc0.setForeground(ModernColors.BLUE); - JLabel lowIOPerformanceModeDesc1 = new JLabel("此项会覆盖 \"文件计算线程池大小\" 配置."); - lowIOPerformanceModeDesc1.setForeground(ModernColors.YELLOW); + //单线程模式 + JLabel singleThreadModeDesc0 = new JLabel("此项选中后, 将会限制生成缓存的线程数至单线程, 对于机械盘等低 IO 性能的服务器可能会有性能提升."); + singleThreadModeDesc0.setForeground(ModernColors.BLUE); + JLabel singleThreadModeDesc1 = new JLabel("此项会覆盖 \"文件计算线程池大小\" 配置."); + singleThreadModeDesc1.setForeground(ModernColors.YELLOW); //文件线程池大小 Box fileThreadPoolSizeBox = Box.createHorizontalBox(); @@ -82,7 +83,7 @@ public static JPanel createPanel() { FILE_THREAD_POOL_SIZE_SPINNER.setModel(fileThreadPoolSizeSpinnerModel); JSpinner.NumberEditor portSpinnerEditor = new JSpinner.NumberEditor(FILE_THREAD_POOL_SIZE_SPINNER, "#"); FILE_THREAD_POOL_SIZE_SPINNER.setEditor(portSpinnerEditor); - fileThreadPoolSizeBox.add(new JLabel("文件计算线程池大小 (重启生效): ")); + fileThreadPoolSizeBox.add(new JLabel("文件计算线程池大小: ")); fileThreadPoolSizeBox.add(FILE_THREAD_POOL_SIZE_SPINNER); JLabel fileThreadPoolSizeDesc0 = new JLabel("此项决定在生成资源缓存时同时计算文件校验码的线程数, 默认为 0, 即为逻辑处理器数量 * 2."); fileThreadPoolSizeDesc0.setForeground(ModernColors.BLUE); @@ -106,9 +107,9 @@ public static JPanel createPanel() { settingsPanel.add(autoUpdateDesc); settingsPanel.add(closeOperationBox); settingsPanel.add(closeOperationsDesc); - settingsPanel.add(LOW_IO_PERFORMANCE_MODE); - settingsPanel.add(lowIOPerformanceModeDesc0); - settingsPanel.add(lowIOPerformanceModeDesc1); + settingsPanel.add(SINGLE_THREAD_MODE); + settingsPanel.add(singleThreadModeDesc0); + settingsPanel.add(singleThreadModeDesc1); settingsPanel.add(fileThreadPoolSizeBox); settingsPanel.add(fileThreadPoolSizeDesc0); settingsPanel.add(fileThreadPoolSizeDesc1); @@ -152,7 +153,7 @@ public static void applyConfiguration() AUTO_CHECK_UPDATES.setSelected(CONFIG.isAutoCheckUpdates()); AUTO_UPDATE.setSelected(CONFIG.isAutoUpdate()); CLOSE_OPERATION_COMBO_BOX.setSelectedIndex(CONFIG.getCloseOperation()); - LOW_IO_PERFORMANCE_MODE.setSelected(CONFIG.isLowIOPerformanceMode()); + SINGLE_THREAD_MODE.setSelected(CONFIG.isSingleThreadMode()); FILE_THREAD_POOL_SIZE_SPINNER.setValue(CONFIG.getFileThreadPoolSize()); ENABLE_DEBUG_MODE.setSelected(CONFIG.isDebugMode()); } @@ -167,10 +168,13 @@ private static void saveConfiguration() CONFIG.setAutoCheckUpdates(AUTO_CHECK_UPDATES.isSelected()); CONFIG.setAutoUpdate(AUTO_UPDATE.isSelected()); CONFIG.setCloseOperation(CLOSE_OPERATION_COMBO_BOX.getSelectedIndex()); - CONFIG.setLowIOPerformanceMode(LOW_IO_PERFORMANCE_MODE.isSelected()); + CONFIG.setSingleThreadMode(SINGLE_THREAD_MODE.isSelected()); CONFIG.setFileThreadPoolSize((int) FILE_THREAD_POOL_SIZE_SPINNER.getValue()); CONFIG.setDebugMode(ENABLE_DEBUG_MODE.isSelected()); + //重载文件线程池大小 + BalloonServer.initFileThreadPool(); + try { ConfigurationManager.saveConfigurationToFile(CONFIG, "./", "balloonserver"); GLOBAL_LOGGER.info("成功保存主程序配置文件."); diff --git a/src/main/java/github/kasuminova/balloonserver/gui/ruleeditor/RuleEditorActionListener.java b/src/main/java/github/kasuminova/balloonserver/gui/ruleeditor/RuleEditorActionListener.java index ebcca12..6a242e8 100644 --- a/src/main/java/github/kasuminova/balloonserver/gui/ruleeditor/RuleEditorActionListener.java +++ b/src/main/java/github/kasuminova/balloonserver/gui/ruleeditor/RuleEditorActionListener.java @@ -4,7 +4,7 @@ import cn.hutool.core.io.file.FileReader; import com.alibaba.fastjson2.JSONArray; import github.kasuminova.balloonserver.BalloonServer; -import github.kasuminova.balloonserver.servers.ServerInterface; +import github.kasuminova.balloonserver.servers.GUIServerInterface; import github.kasuminova.balloonserver.servers.localserver.IntegratedServerInterface; import github.kasuminova.balloonserver.servers.remoteserver.RemoteClientInterface; import github.kasuminova.balloonserver.utils.GUILogger; @@ -24,10 +24,10 @@ public class RuleEditorActionListener implements ActionListener { protected final JList ruleList; protected final List rules; - protected final ServerInterface serverInterface; + protected final GUIServerInterface serverInterface; protected final GUILogger logger; - public RuleEditorActionListener(JList ruleList, List rules, ServerInterface serverInterface, GUILogger logger) { + public RuleEditorActionListener(JList ruleList, List rules, GUIServerInterface serverInterface, GUILogger logger) { this.ruleList = ruleList; this.rules = rules; this.serverInterface = serverInterface; diff --git a/src/main/java/github/kasuminova/balloonserver/servers/AbstractGUIServer.java b/src/main/java/github/kasuminova/balloonserver/servers/AbstractGUIServer.java new file mode 100644 index 0000000..6f2a80d --- /dev/null +++ b/src/main/java/github/kasuminova/balloonserver/servers/AbstractGUIServer.java @@ -0,0 +1,262 @@ +package github.kasuminova.balloonserver.servers; + +import github.kasuminova.balloonserver.configurations.IntegratedServerConfig; +import github.kasuminova.balloonserver.gui.SmoothProgressBar; +import github.kasuminova.balloonserver.gui.ruleeditor.RuleEditorActionListener; +import github.kasuminova.balloonserver.httpserver.HttpServerInterface; +import github.kasuminova.balloonserver.servers.localserver.AddUpdateRule; +import github.kasuminova.balloonserver.servers.localserver.DeleteUpdateRule; +import github.kasuminova.balloonserver.utils.MiscUtils; + +import javax.swing.*; +import javax.swing.border.TitledBorder; +import javax.swing.text.BadLocationException; +import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +import static github.kasuminova.balloonserver.BalloonServer.MAIN_FRAME; +import static github.kasuminova.balloonserver.utils.SvgIcons.*; + +/** + * 抽象服务端面板示例 + */ +public abstract class AbstractGUIServer extends AbstractServer { + protected static final int CONTROL_PANEL_WIDTH = 350; + protected final JPanel controlPanel = new JPanel(new BorderLayout()); + //IP 输入框 + protected final JTextField IPTextField = new JTextField("0.0.0.0"); + //端口输入框 + protected final JSpinner portSpinner = new JSpinner(); + //Jks 证书密码 + protected final JPasswordField JksSslPassField = new JPasswordField(); + //资源文件夹输入框 + protected final JTextField mainDirTextField = new JTextField("/res"); + //实时文件监听 + protected final JCheckBox fileChangeListener = new JCheckBox("启用实时文件监听", true); + //旧版兼容模式 + protected final JCheckBox compatibleMode = new JCheckBox("启用旧版兼容"); + //证书文件名(不可编辑) + protected final JTextField JksSslTextField = new JTextField("请选择证书文件"); + //普通模式 + protected final JList commonMode = new JList<>(); + //补全模式 + protected final JList onceMode = new JList<>(); + protected final SmoothProgressBar statusProgressBar = new SmoothProgressBar(1000, 250); + protected final JTextPane logPane = new JTextPane(); + protected final JPanel logPanel = new JPanel(new BorderLayout()); + protected HttpServerInterface httpServerInterface; + + protected AbstractGUIServer(String serverName) { + super(serverName); + + //设置 Logger,主体为 logPanel + logger.setLogPane(logPane); + loadLogPanel(); + } + + /** + * 载入 Log 日志窗口面板 + */ + protected void loadLogPanel() { + logPanel.setMinimumSize(new Dimension((int) (MAIN_FRAME.getWidth() * 0.5), 0)); + + logPanel.setBorder(new TitledBorder("服务端实例日志")); + logPane.setEditable(false); + JScrollPane logScrollPane = new JScrollPane(logPane); + logPanel.add(logScrollPane, BorderLayout.CENTER); + + //日志窗口菜单 + JPopupMenu logPaneMenu = new JPopupMenu(); + JMenuItem cleanLogPane = new JMenuItem("清空日志", DELETE_ICON); + cleanLogPane.addActionListener(e -> { + try { + logPane.getDocument().remove(0, logPane.getDocument().getLength()); + logger.info("已清空当前服务端实例日志窗口."); + } catch (BadLocationException ignored) {} + }); + logPaneMenu.add(cleanLogPane); + logPane.addMouseListener(new LogPaneMouseAdapter(logPaneMenu, logPane)); + } + + protected Box loadIPPortBox() { + //IP 配置 + Box IPPortBox = Box.createHorizontalBox(); + IPPortBox.add(new JLabel("监听 IP:")); + IPPortBox.add(IPTextField); + //端口配置 + SpinnerNumberModel portSpinnerModel = new SpinnerNumberModel(8080, 1, 65535, 1); + portSpinner.setModel(portSpinnerModel); + JSpinner.NumberEditor portSpinnerEditor = new JSpinner.NumberEditor(portSpinner, "#"); + portSpinner.setEditor(portSpinnerEditor); + IPPortBox.add(new JLabel(" 端口:")); + IPPortBox.add(portSpinner); + + return IPPortBox; + } + + protected Box loadMainDirBox() { + //资源文件夹 + Box mainDirBox = Box.createHorizontalBox(); + JLabel mainDirLabel = new JLabel("资源文件夹:"); + mainDirTextField.putClientProperty("JTextField.showClearButton", true); + mainDirTextField.setToolTipText(""" + 仅支持程序当前目录下的文件夹或子文件夹,请勿输入其他文件夹。 + 默认为 /res , 也可输入其他文件夹, 如 /resources、/content、/.minecraft 等."""); + mainDirBox.add(mainDirLabel); + mainDirBox.add(mainDirTextField); + + return mainDirBox; + } + + protected abstract Box loadJksSslBox(); + + protected Box loadJksSslPassBox() { + Box JksSslPassBox = Box.createHorizontalBox(); + JksSslPassBox.add(new JLabel("JKS 证书密码:")); + JksSslPassBox.add(JksSslPassField); + return JksSslPassBox; + } + + protected Component loadCommonModePanel() { + //普通更新模式 + JPanel commonModePanel = new JPanel(); + commonModePanel.add(commonMode); + + JScrollPane commonModeScrollPane = new JScrollPane( + commonModePanel, + JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, + JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); + commonModeScrollPane.setBorder(new TitledBorder("普通更新模式")); + commonModeScrollPane.setPreferredSize(new Dimension(0,200)); + + //菜单 + JPopupMenu commonModeMenu = new JPopupMenu(); + JMenuItem openCommonModeRuleEditor = new JMenuItem("打开更新规则编辑器"); + openCommonModeRuleEditor.setIcon(EDIT_ICON); + //普通更新规则编辑器 + openCommonModeRuleEditor.addActionListener(new RuleEditorActionListener(commonMode, commonModeList, (GUIServerInterface) getServerInterface(), logger)); + commonModeMenu.add(openCommonModeRuleEditor); + commonModeMenu.addSeparator(); + //添加更新规则 + JMenuItem addNewCommonRule = new JMenuItem("添加更新规则"); + addNewCommonRule.setIcon(PLUS_ICON); + addNewCommonRule.addActionListener(new AddUpdateRule(commonMode, commonModeList, MAIN_FRAME)); + commonModeMenu.add(addNewCommonRule); + //删除指定规则 + JMenuItem deleteCommonRule = new JMenuItem("删除选定的规则"); + deleteCommonRule.setIcon(REMOVE_ICON); + deleteCommonRule.addActionListener(new DeleteUpdateRule(commonMode, commonModeList, MAIN_FRAME)); + commonModeMenu.add(deleteCommonRule); + //鼠标监听 + RuleListMenuMouseAdapter commonRuleListMenuListener = new RuleListMenuMouseAdapter(commonModeMenu, commonMode); + commonMode.addMouseListener(commonRuleListMenuListener); + commonModePanel.addMouseListener(commonRuleListMenuListener); + + return commonModeScrollPane; + } + + protected Component loadOnceModePanel() { + //补全更新模式 + JPanel onceModePanel = new JPanel(); + onceModePanel.add(onceMode); + + JScrollPane onceModeScrollPane = new JScrollPane( + onceModePanel, + JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, + JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); + onceModeScrollPane.setBorder(new TitledBorder("补全更新模式")); + onceModeScrollPane.setPreferredSize(new Dimension(0,200)); + + //菜单 + JPopupMenu onceModeMenu = new JPopupMenu(); + JMenuItem openOnceModeRuleEditor = new JMenuItem("打开更新规则编辑器"); + openOnceModeRuleEditor.setIcon(EDIT_ICON); + //补全更新规则编辑器 + openOnceModeRuleEditor.addActionListener(new RuleEditorActionListener(onceMode, onceModeList, (GUIServerInterface) getServerInterface(), logger)); + onceModeMenu.add(openOnceModeRuleEditor); + onceModeMenu.addSeparator(); + //添加更新规则 + JMenuItem addNewOnceRule = new JMenuItem("添加更新规则"); + addNewOnceRule.setIcon(PLUS_ICON); + addNewOnceRule.addActionListener(new AddUpdateRule(onceMode, onceModeList, MAIN_FRAME)); + onceModeMenu.add(addNewOnceRule); + //删除指定规则 + JMenuItem deleteOnceRule = new JMenuItem("删除选定的规则"); + deleteOnceRule.setIcon(REMOVE_ICON); + deleteOnceRule.addActionListener(new DeleteUpdateRule(onceMode, onceModeList, MAIN_FRAME)); + onceModeMenu.add(deleteOnceRule); + //鼠标监听 + RuleListMenuMouseAdapter onceRuleListMenuListener = new RuleListMenuMouseAdapter(onceModeMenu, onceMode); + onceMode.addMouseListener(onceRuleListMenuListener); + onceModePanel.addMouseListener(onceRuleListMenuListener); + + return onceModeScrollPane; + } + + protected JPanel loadExtraFeaturesPanel() { + JPanel extraFeaturesPanel = new JPanel(new BorderLayout()); + //实时文件监听 + fileChangeListener.setToolTipText(""" + 开启后,启动服务器的同时会启动文件监听服务. + 文件监听服务会每隔 5 - 7 秒会监听资源文件夹的变化,如果资源一有变化会立即重新生成资源缓存. + 注意:不推荐在超大文件夹(10000 文件/文件夹 以上)上使用此功能,可能会造成 I/O 卡顿."""); + + compatibleMode.setToolTipText(""" + 开启后,服务端将兼容 4.x.x 版本的所有类型客户端. + 但是同时也会造成一定的性能下降."""); + + extraFeaturesPanel.add(fileChangeListener, BorderLayout.WEST); + extraFeaturesPanel.add(compatibleMode, BorderLayout.EAST); + + return extraFeaturesPanel; + } + + /** + * 重置主窗口状态栏进度条 + */ + protected void resetStatusProgressBar() { + statusProgressBar.setVisible(false); + statusProgressBar.setIndeterminate(false); + statusProgressBar.reset(); + } + + /** + * 返回当前服务器实例的 HTTP 服务器接口 + * + * @return HttpServerInterface + */ + + protected abstract JPanel getPanel(); + + protected abstract Component loadStatusBar(); + + protected abstract Component loadControlPanel(); + + protected abstract void loadConfigurationFromFile(); + + protected abstract void updateGUIConfig(IntegratedServerConfig config); + + protected abstract void reloadConfigurationFromGUI(); + + protected abstract void saveConfigurationToFile(); + + public HttpServerInterface getHttpServerInterface() { + return httpServerInterface; + } + + private static class RuleListMenuMouseAdapter extends MouseAdapter { + private final JPopupMenu ruleListMenu; + private final JList ruleList; + + private RuleListMenuMouseAdapter(JPopupMenu ruleListMenu, JList ruleList) { + this.ruleListMenu = ruleListMenu; + this.ruleList = ruleList; + } + + @Override + public void mouseReleased(MouseEvent e) { + if (e.isPopupTrigger()) MiscUtils.showPopupMenu(ruleListMenu, ruleList, e); + } + } +} diff --git a/src/main/java/github/kasuminova/balloonserver/servers/AbstractServer.java b/src/main/java/github/kasuminova/balloonserver/servers/AbstractServer.java index 826d20b..b32dcb0 100644 --- a/src/main/java/github/kasuminova/balloonserver/servers/AbstractServer.java +++ b/src/main/java/github/kasuminova/balloonserver/servers/AbstractServer.java @@ -1,34 +1,13 @@ package github.kasuminova.balloonserver.servers; -import github.kasuminova.balloonserver.configurations.IntegratedServerConfig; -import github.kasuminova.balloonserver.gui.SmoothProgressBar; -import github.kasuminova.balloonserver.gui.ruleeditor.RuleEditorActionListener; -import github.kasuminova.balloonserver.httpserver.HttpServerInterface; -import github.kasuminova.balloonserver.servers.localserver.AddUpdateRule; -import github.kasuminova.balloonserver.servers.localserver.DeleteUpdateRule; import github.kasuminova.balloonserver.utils.GUILogger; -import github.kasuminova.balloonserver.utils.MiscUtils; -import javax.swing.*; -import javax.swing.border.TitledBorder; -import javax.swing.text.BadLocationException; -import java.awt.*; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; -import static github.kasuminova.balloonserver.BalloonServer.MAIN_FRAME; -import static github.kasuminova.balloonserver.utils.SvgIcons.*; - -/** - * 抽象服务端面板示例 - */ public abstract class AbstractServer { - protected static final int CONTROL_PANEL_WIDTH = 350; protected final long start = System.currentTimeMillis(); - protected final JPanel controlPanel = new JPanel(new BorderLayout()); protected final List commonModeList = new ArrayList<>(0); protected final List onceModeList = new ArrayList<>(0); //服务器启动状态 @@ -36,242 +15,15 @@ public abstract class AbstractServer { protected final AtomicBoolean isStarting = new AtomicBoolean(false); //服务端是否在生成缓存,防止同一时间多个线程生成缓存导致程序混乱 protected final AtomicBoolean isGenerating = new AtomicBoolean(false); - //IP 输入框 - protected final JTextField IPTextField = new JTextField("0.0.0.0"); - //端口输入框 - protected final JSpinner portSpinner = new JSpinner(); - //Jks 证书密码 - protected final JPasswordField JksSslPassField = new JPasswordField(); - //资源文件夹输入框 - protected final JTextField mainDirTextField = new JTextField("/res"); - //实时文件监听 - protected final JCheckBox fileChangeListener = new JCheckBox("启用实时文件监听", true); - //旧版兼容模式 - protected final JCheckBox compatibleMode = new JCheckBox("启用旧版兼容"); - //证书文件名(不可编辑) - protected final JTextField JksSslTextField = new JTextField("请选择证书文件"); - //普通模式 - protected final JList commonMode = new JList<>(); - //补全模式 - protected final JList onceMode = new JList<>(); - protected final SmoothProgressBar statusProgressBar = new SmoothProgressBar(1000, 250); protected final GUILogger logger; protected final String serverName; - protected final JTextPane logPane = new JTextPane(); - protected final JPanel logPanel = new JPanel(new BorderLayout()); - protected HttpServerInterface httpServerInterface; protected AbstractServer(String serverName) { this.serverName = serverName; //设置 Logger,主体为 logPanel - logger = new GUILogger(serverName, logPane); - loadLogPanel(); - } - - /** - * 载入 Log 日志窗口面板 - */ - protected void loadLogPanel() { - logPanel.setMinimumSize(new Dimension((int) (MAIN_FRAME.getWidth() * 0.5), 0)); - - logPanel.setBorder(new TitledBorder("服务端实例日志")); - logPane.setEditable(false); - JScrollPane logScrollPane = new JScrollPane(logPane); - logPanel.add(logScrollPane, BorderLayout.CENTER); - - //日志窗口菜单 - JPopupMenu logPaneMenu = new JPopupMenu(); - JMenuItem cleanLogPane = new JMenuItem("清空日志", DELETE_ICON); - cleanLogPane.addActionListener(e -> { - try { - logPane.getDocument().remove(0, logPane.getDocument().getLength()); - logger.info("已清空当前服务端实例日志窗口."); - } catch (BadLocationException ignored) {} - }); - logPaneMenu.add(cleanLogPane); - logPane.addMouseListener(new LogPaneMouseAdapter(logPaneMenu, logPane)); - } - - protected Box loadIPPortBox() { - //IP 配置 - Box IPPortBox = Box.createHorizontalBox(); - IPPortBox.add(new JLabel("监听 IP:")); - IPPortBox.add(IPTextField); - //端口配置 - SpinnerNumberModel portSpinnerModel = new SpinnerNumberModel(8080, 1, 65535, 1); - portSpinner.setModel(portSpinnerModel); - JSpinner.NumberEditor portSpinnerEditor = new JSpinner.NumberEditor(portSpinner, "#"); - portSpinner.setEditor(portSpinnerEditor); - IPPortBox.add(new JLabel(" 端口:")); - IPPortBox.add(portSpinner); - - return IPPortBox; - } - - protected Box loadMainDirBox() { - //资源文件夹 - Box mainDirBox = Box.createHorizontalBox(); - JLabel mainDirLabel = new JLabel("资源文件夹:"); - mainDirTextField.putClientProperty("JTextField.showClearButton", true); - mainDirTextField.setToolTipText(""" - 仅支持程序当前目录下的文件夹或子文件夹,请勿输入其他文件夹。 - 默认为 /res , 也可输入其他文件夹, 如 /resources、/content、/.minecraft 等."""); - mainDirBox.add(mainDirLabel); - mainDirBox.add(mainDirTextField); - - return mainDirBox; - } - - protected abstract Box loadJksSslBox(); - - protected Box loadJksSslPassBox() { - Box JksSslPassBox = Box.createHorizontalBox(); - JksSslPassBox.add(new JLabel("JKS 证书密码:")); - JksSslPassBox.add(JksSslPassField); - return JksSslPassBox; - } - - protected Component loadCommonModePanel() { - //普通更新模式 - JPanel commonModePanel = new JPanel(); - commonModePanel.add(commonMode); - - JScrollPane commonModeScrollPane = new JScrollPane( - commonModePanel, - JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, - JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); - commonModeScrollPane.setBorder(new TitledBorder("普通更新模式")); - commonModeScrollPane.setPreferredSize(new Dimension(0,200)); - - //菜单 - JPopupMenu commonModeMenu = new JPopupMenu(); - JMenuItem openCommonModeRuleEditor = new JMenuItem("打开更新规则编辑器"); - openCommonModeRuleEditor.setIcon(EDIT_ICON); - //普通更新规则编辑器 - openCommonModeRuleEditor.addActionListener(new RuleEditorActionListener(commonMode, commonModeList, getServerInterface(), logger)); - commonModeMenu.add(openCommonModeRuleEditor); - commonModeMenu.addSeparator(); - //添加更新规则 - JMenuItem addNewCommonRule = new JMenuItem("添加更新规则"); - addNewCommonRule.setIcon(PLUS_ICON); - addNewCommonRule.addActionListener(new AddUpdateRule(commonMode, commonModeList, MAIN_FRAME)); - commonModeMenu.add(addNewCommonRule); - //删除指定规则 - JMenuItem deleteCommonRule = new JMenuItem("删除选定的规则"); - deleteCommonRule.setIcon(REMOVE_ICON); - deleteCommonRule.addActionListener(new DeleteUpdateRule(commonMode, commonModeList, MAIN_FRAME)); - commonModeMenu.add(deleteCommonRule); - //鼠标监听 - RuleListMenuMouseAdapter commonRuleListMenuListener = new RuleListMenuMouseAdapter(commonModeMenu, commonMode); - commonMode.addMouseListener(commonRuleListMenuListener); - commonModePanel.addMouseListener(commonRuleListMenuListener); - - return commonModeScrollPane; - } - - protected Component loadOnceModePanel() { - //补全更新模式 - JPanel onceModePanel = new JPanel(); - onceModePanel.add(onceMode); - - JScrollPane onceModeScrollPane = new JScrollPane( - onceModePanel, - JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, - JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); - onceModeScrollPane.setBorder(new TitledBorder("补全更新模式")); - onceModeScrollPane.setPreferredSize(new Dimension(0,200)); - - //菜单 - JPopupMenu onceModeMenu = new JPopupMenu(); - JMenuItem openOnceModeRuleEditor = new JMenuItem("打开更新规则编辑器"); - openOnceModeRuleEditor.setIcon(EDIT_ICON); - //补全更新规则编辑器 - openOnceModeRuleEditor.addActionListener(new RuleEditorActionListener(onceMode, onceModeList, getServerInterface(), logger)); - onceModeMenu.add(openOnceModeRuleEditor); - onceModeMenu.addSeparator(); - //添加更新规则 - JMenuItem addNewOnceRule = new JMenuItem("添加更新规则"); - addNewOnceRule.setIcon(PLUS_ICON); - addNewOnceRule.addActionListener(new AddUpdateRule(onceMode, onceModeList, MAIN_FRAME)); - onceModeMenu.add(addNewOnceRule); - //删除指定规则 - JMenuItem deleteOnceRule = new JMenuItem("删除选定的规则"); - deleteOnceRule.setIcon(REMOVE_ICON); - deleteOnceRule.addActionListener(new DeleteUpdateRule(onceMode, onceModeList, MAIN_FRAME)); - onceModeMenu.add(deleteOnceRule); - //鼠标监听 - RuleListMenuMouseAdapter onceRuleListMenuListener = new RuleListMenuMouseAdapter(onceModeMenu, onceMode); - onceMode.addMouseListener(onceRuleListMenuListener); - onceModePanel.addMouseListener(onceRuleListMenuListener); - - return onceModeScrollPane; - } - - protected JPanel loadExtraFeaturesPanel() { - JPanel extraFeaturesPanel = new JPanel(new BorderLayout()); - //实时文件监听 - fileChangeListener.setToolTipText(""" - 开启后,启动服务器的同时会启动文件监听服务. - 文件监听服务会每隔 5 - 7 秒会监听资源文件夹的变化,如果资源一有变化会立即重新生成资源缓存. - 注意:不推荐在超大文件夹(10000 文件/文件夹 以上)上使用此功能,可能会造成 I/O 卡顿."""); - - compatibleMode.setToolTipText(""" - 开启后,服务端将兼容 4.x.x 版本的所有类型客户端. - 但是同时也会造成一定的性能下降."""); - - extraFeaturesPanel.add(fileChangeListener, BorderLayout.WEST); - extraFeaturesPanel.add(compatibleMode, BorderLayout.EAST); - - return extraFeaturesPanel; - } - - /** - * 重置主窗口状态栏进度条 - */ - protected void resetStatusProgressBar() { - statusProgressBar.setVisible(false); - statusProgressBar.setIndeterminate(false); - statusProgressBar.reset(); - } - - /** - * 返回当前服务器实例的 HTTP 服务器接口 - * - * @return HttpServerInterface - */ - public HttpServerInterface getHttpServerInterface() { - return httpServerInterface; + logger = new GUILogger(serverName); } - protected abstract JPanel getPanel(); - protected abstract ServerInterface getServerInterface(); - - protected abstract Component loadStatusBar(); - - protected abstract Component loadControlPanel(); - - protected abstract void loadConfigurationFromFile(); - - protected abstract void updateGUIConfig(IntegratedServerConfig config); - - protected abstract void reloadConfigurationFromGUI(); - - protected abstract void saveConfigurationToFile(); - - private static class RuleListMenuMouseAdapter extends MouseAdapter { - private final JPopupMenu ruleListMenu; - private final JList ruleList; - - private RuleListMenuMouseAdapter(JPopupMenu ruleListMenu, JList ruleList) { - this.ruleListMenu = ruleListMenu; - this.ruleList = ruleList; - } - - @Override - public void mouseReleased(MouseEvent e) { - if (e.isPopupTrigger()) MiscUtils.showPopupMenu(ruleListMenu, ruleList, e); - } - } } diff --git a/src/main/java/github/kasuminova/balloonserver/servers/GUIServerInterface.java b/src/main/java/github/kasuminova/balloonserver/servers/GUIServerInterface.java new file mode 100644 index 0000000..2dbe427 --- /dev/null +++ b/src/main/java/github/kasuminova/balloonserver/servers/GUIServerInterface.java @@ -0,0 +1,18 @@ +package github.kasuminova.balloonserver.servers; + +import github.kasuminova.balloonserver.gui.SmoothProgressBar; + +import java.awt.*; + +public interface GUIServerInterface extends ServerInterface { + String getResJsonFileExtensionName(); + + String getLegacyResJsonFileExtensionName(); + + //获取状态栏进度条 + SmoothProgressBar getStatusProgressBar(); + + void setStatusLabelText(String text, Color fg); + + void resetStatusProgressBar(); +} \ No newline at end of file diff --git a/src/main/java/github/kasuminova/balloonserver/servers/ServerInterface.java b/src/main/java/github/kasuminova/balloonserver/servers/ServerInterface.java index 587cb84..c6a4a9f 100644 --- a/src/main/java/github/kasuminova/balloonserver/servers/ServerInterface.java +++ b/src/main/java/github/kasuminova/balloonserver/servers/ServerInterface.java @@ -1,9 +1,7 @@ package github.kasuminova.balloonserver.servers; import github.kasuminova.balloonserver.configurations.IntegratedServerConfig; -import github.kasuminova.balloonserver.gui.SmoothProgressBar; -import java.awt.*; import java.util.concurrent.atomic.AtomicBoolean; public interface ServerInterface { @@ -28,33 +26,22 @@ public interface ServerInterface { */ void saveConfig(); - //获取 index.json 字符串 - String getIndexJson(); - - String getResJsonFileExtensionName(); - - String getLegacyResJsonFileExtensionName(); - //设置新的旧版文件结构 JSON void setLegacyResJson(String newLegacyResJson); //获取旧版文件结构 JSON String getLegacyResJson(); - //获取状态栏进度条 - SmoothProgressBar getStatusProgressBar(); - - void setStatusLabelText(String text, Color fg); - - //设置新的文件结构 JSON - void setResJson(String newResJson); - - void resetStatusProgressBar(); - AtomicBoolean isGenerating(); AtomicBoolean isStarted(); //获取文件结构 JSON String getResJson(); + + //设置新的文件结构 JSON + void setResJson(String newResJson); + + //获取 index.json 字符串 + String getIndexJson(); } \ No newline at end of file diff --git a/src/main/java/github/kasuminova/balloonserver/servers/localserver/IntegratedServer.java b/src/main/java/github/kasuminova/balloonserver/servers/localserver/IntegratedServer.java index 13ce169..d65baed 100644 --- a/src/main/java/github/kasuminova/balloonserver/servers/localserver/IntegratedServer.java +++ b/src/main/java/github/kasuminova/balloonserver/servers/localserver/IntegratedServer.java @@ -12,7 +12,7 @@ import github.kasuminova.balloonserver.gui.SmoothProgressBar; import github.kasuminova.balloonserver.gui.layoutmanager.VFlowLayout; import github.kasuminova.balloonserver.httpserver.HttpServer; -import github.kasuminova.balloonserver.servers.AbstractServer; +import github.kasuminova.balloonserver.servers.AbstractGUIServer; import github.kasuminova.balloonserver.utils.*; import github.kasuminova.balloonserver.utils.filecacheutils.JsonCacheUtils; @@ -32,7 +32,7 @@ /** * IntegratedServer 集成服务端面板实例 */ -public class IntegratedServer extends AbstractServer { +public class IntegratedServer extends AbstractGUIServer { protected static final Dimension REQUEST_LIST_FRAME_SIZE = new Dimension(400,750); protected final JSONObject index = new JSONObject(); protected static final String RES_JSON_FILE_EXTENSION_NAME = "res-cache"; @@ -50,7 +50,6 @@ public class IntegratedServer extends AbstractServer { JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); protected final JPanel littleServerPanel = new JPanel(new BorderLayout()); protected final JButton startOrStop = new JButton("保存配置并启动服务器"); - protected HttpServer server; protected String indexJson = null; protected String resJson = null; diff --git a/src/main/java/github/kasuminova/balloonserver/servers/localserver/IntegratedServerInterface.java b/src/main/java/github/kasuminova/balloonserver/servers/localserver/IntegratedServerInterface.java index 53cabb5..891f599 100644 --- a/src/main/java/github/kasuminova/balloonserver/servers/localserver/IntegratedServerInterface.java +++ b/src/main/java/github/kasuminova/balloonserver/servers/localserver/IntegratedServerInterface.java @@ -1,6 +1,6 @@ package github.kasuminova.balloonserver.servers.localserver; -import github.kasuminova.balloonserver.servers.ServerInterface; +import github.kasuminova.balloonserver.servers.GUIServerInterface; import github.kasuminova.balloonserver.utils.GUILogger; import javax.swing.*; @@ -8,7 +8,7 @@ /** * LittleServer 面板向外开放的接口,大部分内容都在此处交互。 */ -public interface IntegratedServerInterface extends ServerInterface { +public interface IntegratedServerInterface extends GUIServerInterface { GUILogger getLogger(); JPanel getRequestListPanel(); diff --git a/src/main/java/github/kasuminova/balloonserver/servers/remoteserver/RemoteIntegratedServerClient.java b/src/main/java/github/kasuminova/balloonserver/servers/remoteserver/RemoteIntegratedServerClient.java index e9da866..98ee75f 100644 --- a/src/main/java/github/kasuminova/balloonserver/servers/remoteserver/RemoteIntegratedServerClient.java +++ b/src/main/java/github/kasuminova/balloonserver/servers/remoteserver/RemoteIntegratedServerClient.java @@ -10,7 +10,7 @@ import github.kasuminova.balloonserver.gui.SmoothProgressBar; import github.kasuminova.balloonserver.gui.layoutmanager.VFlowLayout; import github.kasuminova.balloonserver.remoteclient.RemoteClient; -import github.kasuminova.balloonserver.servers.AbstractServer; +import github.kasuminova.balloonserver.servers.AbstractGUIServer; import github.kasuminova.balloonserver.utils.GUILogger; import github.kasuminova.balloonserver.utils.IPAddressUtil; import github.kasuminova.balloonserver.utils.ModernColors; @@ -35,7 +35,7 @@ * RemoteIntegratedClient 远程服务器客户端实例 * @author Kasumi_Nova */ -public class RemoteIntegratedServerClient extends AbstractServer { +public class RemoteIntegratedServerClient extends AbstractGUIServer { protected final RemoteClientConfig config = new RemoteClientConfig(); protected final JPanel remoteClientPanel = new JPanel(new BorderLayout()); protected final JPanel remotePanel = new JPanel(new BorderLayout()); @@ -165,16 +165,6 @@ public String getIndexJson() { return null; } - @Override - public String getResJsonFileExtensionName() { - return null; - } - - @Override - public String getLegacyResJsonFileExtensionName() { - return null; - } - @Override public String getLegacyResJson() { return null; @@ -185,21 +175,6 @@ public void setLegacyResJson(String newLegacyResJson) { } - @Override - public SmoothProgressBar getStatusProgressBar() { - return null; - } - - @Override - public void setStatusLabelText(String text, Color fg) { - - } - - @Override - public void resetStatusProgressBar() { - - } - @Override public AtomicBoolean isGenerating() { return null; diff --git a/src/main/java/github/kasuminova/balloonserver/utils/GUILogger.java b/src/main/java/github/kasuminova/balloonserver/utils/GUILogger.java index 67afcd4..cd806db 100644 --- a/src/main/java/github/kasuminova/balloonserver/utils/GUILogger.java +++ b/src/main/java/github/kasuminova/balloonserver/utils/GUILogger.java @@ -43,7 +43,7 @@ public class GUILogger extends ConsoleLog { private static final int LOG_PANE_MAX_LENGTH = 200000; //行距, 0.1 相当于 1.1 倍行距 private static final float LINE_SPACE_SIZE = 0.1F; - private final JTextPane logPane; + private JTextPane logPane; private final Writer logWriter; /** @@ -59,7 +59,24 @@ public class GUILogger extends ConsoleLog { * @param logPane 要同步的 JTextPane */ public GUILogger(String name, JTextPane logPane) { + this(name); + + setLogPane(logPane); + } + + /** + * 创建一个 super + * + * @param name log 文件名 + */ + public GUILogger(String name) { super(name); + + logPane = null; + logWriter = createLogFile(name); + } + + public void setLogPane(JTextPane logPane) { this.logPane = logPane; //行距设置 @@ -67,8 +84,6 @@ public GUILogger(String name, JTextPane logPane) { StyleConstants.setLineSpacing(lineSpaceAttribute, LINE_SPACE_SIZE); logPane.setParagraphAttributes(lineSpaceAttribute, false); - logWriter = createLogFile(name); - //设置颜色 StyleConstants.setForeground(INFO_ATTRIBUTE, BLUE); StyleConstants.setForeground(WARN_ATTRIBUTE, YELLOW); @@ -76,19 +91,6 @@ public GUILogger(String name, JTextPane logPane) { StyleConstants.setForeground(DEBUG_ATTRIBUTE, PURPLE); } - /** - * 创建一个 super - * - * @param name log 文件名 - */ - public GUILogger(String name) { - super(name); - - logPane = null; - - logWriter = createLogFile(name); - } - /** *

* 创建一个日志文件。