diff --git a/src/main/java/com/serliunx/ddns/ManagerLite.java b/src/main/java/com/serliunx/ddns/ManagerLite.java index 692a35d..856621e 100644 --- a/src/main/java/com/serliunx/ddns/ManagerLite.java +++ b/src/main/java/com/serliunx/ddns/ManagerLite.java @@ -12,10 +12,10 @@ import com.serliunx.ddns.support.InstanceContextHolder; import com.serliunx.ddns.support.SystemInitializer; import com.serliunx.ddns.support.command.CommandCompleter; import com.serliunx.ddns.support.command.CommandDispatcher; -import com.serliunx.ddns.support.command.target.ConfigCommand; import com.serliunx.ddns.support.command.target.HelpCommand; import com.serliunx.ddns.support.command.target.ReloadCommand; import com.serliunx.ddns.support.command.target.StopCommand; +import com.serliunx.ddns.support.command.target.config.ConfigCommand; import com.serliunx.ddns.support.log.JLineAdaptAppender; import org.jline.reader.LineReader; import org.jline.reader.LineReaderBuilder; diff --git a/src/main/java/com/serliunx/ddns/support/command/AbstractCommand.java b/src/main/java/com/serliunx/ddns/support/command/AbstractCommand.java index 8e9564e..dd5fd78 100644 --- a/src/main/java/com/serliunx/ddns/support/command/AbstractCommand.java +++ b/src/main/java/com/serliunx/ddns/support/command/AbstractCommand.java @@ -1,9 +1,14 @@ package com.serliunx.ddns.support.command; import com.serliunx.ddns.ManagerLite; +import org.jline.reader.Candidate; +import org.jline.reader.LineReader; +import org.jline.reader.ParsedLine; import org.slf4j.Logger; +import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; /** * 指令的抽象实现 @@ -39,6 +44,11 @@ public abstract class AbstractCommand implements Command { return subCommands; } + @Override + public synchronized void addSubCommand(Command command) { + subCommands.add(command); + } + @Override public String getDescription() { return description; @@ -49,6 +59,67 @@ public abstract class AbstractCommand implements Command { return usage; } + /** + * 指令逻辑默认实现: 调用子命令 + * + * @param args 当前指令参数 + * @return 成功执行返回真, 否则返回假. (目前没影响) + */ + @Override + public boolean onCommand(String[] args) { + if (!hasArgs(args) || + args.length < 2) { + log.warn("用法 => {}", getUsage()); + return true; + } + + final String subCommand = args[0]; + List subCommands = getSubCommands(); + for (Command command : subCommands) { + if (command.getName().equalsIgnoreCase(subCommand)) { + return command.onCommand(CommandDispatcher.splitArgs(args)); + } + } + return false; + } + + @Override + public List getArgs() { + if (subCommands == null || + subCommands.isEmpty()) { + return new ArrayList<>(); + } + + return subCommands.stream() + .map(Command::getName) + .collect(Collectors.toList()); + } + + @Override + public void onComplete(LineReader reader, ParsedLine line, int index, List candidates) { + if (index < 1) { + return; + } + + final String currentWord = line.word(); + // 补全子命令 + final List subCommands = getSubCommands(); + if (index == 1) { + subCommands.forEach(c -> { + if (c.getName().startsWith(currentWord)) { + candidates.add(new Candidate(c.getName())); + } + }); + } else { // 交给子命令补全 + for (Command c : subCommands) { + if (c.getName().equals(line.words().get(1))) { + c.onComplete(reader, line, index, candidates); + return; + } + } + } + } + protected boolean hasArgs(String[] args) { return args.length > 0; } diff --git a/src/main/java/com/serliunx/ddns/support/command/Command.java b/src/main/java/com/serliunx/ddns/support/command/Command.java index 639cde5..7f1fd7d 100644 --- a/src/main/java/com/serliunx/ddns/support/command/Command.java +++ b/src/main/java/com/serliunx/ddns/support/command/Command.java @@ -37,6 +37,13 @@ public interface Command { */ List getSubCommands(); + /** + * 添加子命令 + * + * @param command 子命令 + */ + void addSubCommand(Command command); + /** * 获取该指令的描述 */ diff --git a/src/main/java/com/serliunx/ddns/support/command/target/ConfigCommand.java b/src/main/java/com/serliunx/ddns/support/command/target/ConfigCommand.java deleted file mode 100644 index 2a55d46..0000000 --- a/src/main/java/com/serliunx/ddns/support/command/target/ConfigCommand.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.serliunx.ddns.support.command.target; - -import com.serliunx.ddns.config.Configuration; -import com.serliunx.ddns.support.command.AbstractCommand; -import org.jline.reader.Candidate; -import org.jline.reader.LineReader; -import org.jline.reader.ParsedLine; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -/** - * 指令: config - * - * @author SerLiunx - * @version 1.0.4 - * @since 2025/1/22 - */ -public class ConfigCommand extends AbstractCommand { - - /** - * 配置信息 - */ - private final Configuration configuration; - - public ConfigCommand(Configuration configuration) { - super("config", null, "调整配置信息", "config <配置项> 新的值"); - this.configuration = configuration; - } - - @Override - public boolean onCommand(String[] args) { - if (!hasArgs(args) || - args.length < 2) { - log.warn("用法 => {}", getUsage()); - return true; - } - final String target = args[0]; - final String value = args[1]; - return configuration.modify(target, value); - } - - @Override - public List getArgs() { - final Map allKeyAndValue; - if (configuration == null || - (allKeyAndValue = configuration.getAllKeyAndValue()) == null) { - return new ArrayList<>(); - } - return new ArrayList<>(allKeyAndValue.keySet()); - } - - @Override - public void onComplete(LineReader reader, ParsedLine line, int index, List candidates) { - if (index < 1) { - return; - } - - final String currentWord = line.word(); - - // 补全配置键 - if (index == 1) { - final Map allKeyAndValue; - if (configuration == null || - (allKeyAndValue = configuration.getAllKeyAndValue()) == null) { - return; - } - allKeyAndValue.keySet().forEach(k -> { - if (k.startsWith(currentWord)) { - candidates.add(new Candidate(k)); - } - }); - } - } -} diff --git a/src/main/java/com/serliunx/ddns/support/command/target/HelpCommand.java b/src/main/java/com/serliunx/ddns/support/command/target/HelpCommand.java index 389bdbe..7ab5342 100644 --- a/src/main/java/com/serliunx/ddns/support/command/target/HelpCommand.java +++ b/src/main/java/com/serliunx/ddns/support/command/target/HelpCommand.java @@ -28,14 +28,21 @@ public class HelpCommand extends AbstractCommand { public boolean onCommand(String[] args) { final Map commands = getAllCommands(); - log.info("=========================================="); if (hasArgs(args)) { final String cmd = args[0]; final Command command = commands.get(cmd); if (command == null) { - log.warn("无法找到指令 {} 的相关信息, 请使用 help 查看可用的指令及帮助!", cmd); + System.out.printf("无法找到指令 %s 的相关信息, 请使用 help 查看可用的指令及帮助!%n", cmd); } else { - log.info("指令:{} - {} - {}", cmd, command.getDescription(), command.getUsage()); + List subCommands = command.getSubCommands(); + if (subCommands == null || + subCommands.isEmpty()) { + System.out.printf("指令:%s - %s - %s%n", cmd, command.getDescription(), command.getUsage()); + } else { + subCommands.forEach(c -> { + System.out.printf("%s - %s - %s%n", c.getName(), c.getDescription(), c.getUsage()); + }); + } } } else { commands.forEach((k, v) -> { @@ -43,12 +50,11 @@ public class HelpCommand extends AbstractCommand { if (k.equals(getName())) { return; } - log.info("{} - {} - {}", k, v.getDescription(), v.getUsage()); + System.out.printf("%s - %s - %s%n", k, v.getDescription(), v.getUsage()); }); - log.info(""); - log.info("使用 help <指令> 来查看更详细的帮助信息."); + System.out.println(); + System.out.println("使用 help <指令> 来查看更详细的帮助信息."); } - log.info("=========================================="); return true; } diff --git a/src/main/java/com/serliunx/ddns/support/command/target/config/ConfigCommand.java b/src/main/java/com/serliunx/ddns/support/command/target/config/ConfigCommand.java new file mode 100644 index 0000000..9274d86 --- /dev/null +++ b/src/main/java/com/serliunx/ddns/support/command/target/config/ConfigCommand.java @@ -0,0 +1,24 @@ +package com.serliunx.ddns.support.command.target.config; + +import com.serliunx.ddns.config.Configuration; +import com.serliunx.ddns.support.command.AbstractCommand; + +import java.util.ArrayList; + +/** + * 指令: config + * + * @author SerLiunx + * @version 1.0.4 + * @since 2025/1/22 + */ +public class ConfigCommand extends AbstractCommand { + + public ConfigCommand(Configuration configuration) { + super("config", new ArrayList<>(), "调整配置信息", "config "); + // 子命令: set + addSubCommand(new ConfigSetCommand(configuration)); + // 子命令: get + addSubCommand(new ConfigGetCommand(configuration)); + } +} diff --git a/src/main/java/com/serliunx/ddns/support/command/target/config/ConfigCommandHelper.java b/src/main/java/com/serliunx/ddns/support/command/target/config/ConfigCommandHelper.java new file mode 100644 index 0000000..e1df6a3 --- /dev/null +++ b/src/main/java/com/serliunx/ddns/support/command/target/config/ConfigCommandHelper.java @@ -0,0 +1,53 @@ +package com.serliunx.ddns.support.command.target.config; + +import com.serliunx.ddns.config.Configuration; +import org.jline.reader.Candidate; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * config 指令相关工具方法 + * + * @author SerLiunx + * @version 1.0.4 + * @since 2025/2/4 + */ +final class ConfigCommandHelper { + + /** + * 获取所有配置键, 作为参数返回 + * + * @param configuration 配置信息 + * @return 配置键集合 + */ + static List getArgs(Configuration configuration) { + final Map allKeyAndValue; + if (configuration == null || + (allKeyAndValue = configuration.getAllKeyAndValue()) == null) { + return new ArrayList<>(); + } + return new ArrayList<>(allKeyAndValue.keySet()); + } + + /** + * 补全配置键 + * + * @param configuration 配置键 + * @param currentWord 当前输入内容 + * @param candidates 候选参数列表 + */ + static void completeConfigKeys(Configuration configuration, String currentWord, List candidates) { + final Map allKeyAndValue; + if (configuration == null || + (allKeyAndValue = configuration.getAllKeyAndValue()) == null) { + return; + } + allKeyAndValue.keySet().forEach(k -> { + if (k.startsWith(currentWord)) { + candidates.add(new Candidate(k)); + } + }); + } +} diff --git a/src/main/java/com/serliunx/ddns/support/command/target/config/ConfigGetCommand.java b/src/main/java/com/serliunx/ddns/support/command/target/config/ConfigGetCommand.java new file mode 100644 index 0000000..175919e --- /dev/null +++ b/src/main/java/com/serliunx/ddns/support/command/target/config/ConfigGetCommand.java @@ -0,0 +1,51 @@ +package com.serliunx.ddns.support.command.target.config; + +import com.serliunx.ddns.config.Configuration; +import com.serliunx.ddns.support.command.AbstractCommand; +import org.jline.reader.Candidate; +import org.jline.reader.LineReader; +import org.jline.reader.ParsedLine; + +import java.util.List; + +/** + * 指令: config get + * + * @author SerLiunx + * @version 1.0.4 + * @since 2025/2/4 + */ +public final class ConfigGetCommand extends AbstractCommand { + + /** + * 配置信息 + */ + private final Configuration configuration; + + public ConfigGetCommand(Configuration configuration) { + super("get", null, "获取指定配置项的值", "config get <配置项>"); + this.configuration = configuration; + } + + @Override + public boolean onCommand(String[] args) { + if (!hasArgs(args) || + args.length < 1) { + log.warn("用法 => {}", getUsage()); + return true; + } + System.out.println(configuration.getString(args[0])); + return true; + } + + @Override + public List getArgs() { + return ConfigCommandHelper.getArgs(configuration); + } + + @Override + public void onComplete(LineReader reader, ParsedLine line, int index, List candidates) { + if (index == 2) + ConfigCommandHelper.completeConfigKeys(configuration, line.word(), candidates); + } +} diff --git a/src/main/java/com/serliunx/ddns/support/command/target/config/ConfigSetCommand.java b/src/main/java/com/serliunx/ddns/support/command/target/config/ConfigSetCommand.java new file mode 100644 index 0000000..4e40ba9 --- /dev/null +++ b/src/main/java/com/serliunx/ddns/support/command/target/config/ConfigSetCommand.java @@ -0,0 +1,52 @@ +package com.serliunx.ddns.support.command.target.config; + +import com.serliunx.ddns.config.Configuration; +import com.serliunx.ddns.support.command.AbstractCommand; +import org.jline.reader.Candidate; +import org.jline.reader.LineReader; +import org.jline.reader.ParsedLine; + +import java.util.List; + +/** + * 指令: config set + * + * @author SerLiunx + * @version 1.0.4 + * @since 2025/2/4 + */ +public final class ConfigSetCommand extends AbstractCommand { + + /** + * 配置信息 + */ + private final Configuration configuration; + + public ConfigSetCommand(Configuration configuration) { + super("set", null, "设置指定配置项的值", "config set <配置项> <新的值>"); + this.configuration = configuration; + } + + @Override + public boolean onCommand(String[] args) { + if (!hasArgs(args) || + args.length < 2) { + log.warn("用法 => {}", getUsage()); + return true; + } + final String target = args[0]; + final String value = args[1]; + return configuration.modify(target, value); + } + + @Override + public List getArgs() { + return ConfigCommandHelper.getArgs(configuration); + } + + @Override + public void onComplete(LineReader reader, ParsedLine line, int index, List candidates) { + if (index == 2) + ConfigCommandHelper.completeConfigKeys(configuration, line.word(), candidates); + } +}