diff --git a/src/main/java/com/serliunx/ddns/ManagerLite.java b/src/main/java/com/serliunx/ddns/ManagerLite.java index 5bee971..572c457 100644 --- a/src/main/java/com/serliunx/ddns/ManagerLite.java +++ b/src/main/java/com/serliunx/ddns/ManagerLite.java @@ -6,13 +6,18 @@ import com.serliunx.ddns.config.PropertiesConfiguration; import com.serliunx.ddns.constant.SystemConstants; import com.serliunx.ddns.core.context.FileInstanceContext; import com.serliunx.ddns.core.context.MultipleSourceInstanceContext; +import com.serliunx.ddns.support.InstanceContextHolder; import com.serliunx.ddns.support.SystemInitializer; +import com.serliunx.ddns.support.command.CommandDispatcher; +import com.serliunx.ddns.support.command.target.HelpCommand; import com.serliunx.ddns.support.log.JLineAdaptAppender; import org.jline.reader.LineReader; import org.jline.reader.LineReaderBuilder; import org.jline.reader.impl.history.DefaultHistory; import org.jline.terminal.Terminal; import org.jline.terminal.TerminalBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; @@ -25,6 +30,11 @@ import java.io.IOException; */ public final class ManagerLite { + /** + * 默认的日志输出 + */ + private static final Logger DEFAULT_LOGGER = LoggerFactory.getLogger(ManagerLite.class); + /** * 配置信息 */ @@ -37,9 +47,19 @@ public final class ManagerLite { * 系统初始化器 */ private static SystemInitializer systemInitializer; + /** + * 指令调度 + */ + private static CommandDispatcher commandDispatcher; + + /** + * 获取默认的日志输出 + */ + public static Logger getLogger() { + return DEFAULT_LOGGER; + } public static void main(String[] args) { - // 配置初始化 initConfiguration(args); @@ -49,6 +69,9 @@ public final class ManagerLite { // 系统初始化 initSystem(); + // 指令初始化 + initCommands(); + Terminal terminal; try { terminal = TerminalBuilder.builder() @@ -67,30 +90,35 @@ public final class ManagerLite { JLineAdaptAppender.setLineReader(lineReader); - String prompt = "client> "; + final String prompt = "client> "; + InstanceContextHolder.setAdditional("command-process"); while (true) { // 该方法会阻塞,直到用户敲回车 try { String cmd = lineReader.readLine(prompt); - // 当用户输入 exit 或 quit,就退出循环 + // 当用户输入 exit,就退出循环 if ("exit".equalsIgnoreCase(cmd)) { break; } - // 在这里可以对用户输入做进一步处理 + commandDispatcher.onCommand(cmd); terminal.flush(); } catch (Exception e) { - System.exit(0); + break; } } - try { - System.exit(0); - terminal.close(); - } catch (IOException e) { - throw new RuntimeException(e); - } + System.exit(0); + } + + /** + * 指令初始化 + */ + private static void initCommands() { + commandDispatcher = CommandDispatcher.getInstance(); + // help + commandDispatcher.register(new HelpCommand()); } /** diff --git a/src/main/java/com/serliunx/ddns/support/command/AbstractCommand.java b/src/main/java/com/serliunx/ddns/support/command/AbstractCommand.java new file mode 100644 index 0000000..d8d1263 --- /dev/null +++ b/src/main/java/com/serliunx/ddns/support/command/AbstractCommand.java @@ -0,0 +1,46 @@ +package com.serliunx.ddns.support.command; + +import java.util.List; + +/** + * 指令的抽象实现 + *
  • 实现公共逻辑及定义具体逻辑 + * + * @author SerLiunx + * @version 1.0.4 + * @since 2025/1/15 + */ +public abstract class AbstractCommand implements Command { + + private final String name; + private final List subCommands; + private final String description; + private final String usage; + + public AbstractCommand(String name, List subCommands, String description, String usage) { + this.name = name; + this.subCommands = subCommands; + this.description = description; + this.usage = usage; + } + + @Override + public String getName() { + return name; + } + + @Override + public List getSubCommands() { + return subCommands; + } + + @Override + public String getDescription() { + return description; + } + + @Override + public String getUsage() { + return usage; + } +} diff --git a/src/main/java/com/serliunx/ddns/support/command/Command.java b/src/main/java/com/serliunx/ddns/support/command/Command.java new file mode 100644 index 0000000..ff23d00 --- /dev/null +++ b/src/main/java/com/serliunx/ddns/support/command/Command.java @@ -0,0 +1,44 @@ +package com.serliunx.ddns.support.command; + +import java.util.List; + +/** + * 指令接口定义 + * + * @author SerLiunx + * @version 1.0.4 + * @since 2025/1/15 + */ +public interface Command { + + /** + * 指令执行逻辑 + * + * @param args 当前指令参数 + * @return 成功执行返回真, 否则返回假. (目前没影响) + */ + boolean onCommand(String[] args); + + /** + * 获取指令名称 + */ + String getName(); + + /** + * 获取子命令 + *
  • 例: cmd c1 c2, 此时 c1为cmd的子命令 + * + * @return 子命令 + */ + List getSubCommands(); + + /** + * 获取该指令的描述 + */ + String getDescription(); + + /** + * 获取该指令的用法 + */ + String getUsage(); +} diff --git a/src/main/java/com/serliunx/ddns/support/command/CommandDispatcher.java b/src/main/java/com/serliunx/ddns/support/command/CommandDispatcher.java new file mode 100644 index 0000000..eed6dcc --- /dev/null +++ b/src/main/java/com/serliunx/ddns/support/command/CommandDispatcher.java @@ -0,0 +1,89 @@ +package com.serliunx.ddns.support.command; + +import com.serliunx.ddns.ManagerLite; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Arrays; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 指令调度器 + * + * @author SerLiunx + * @version 1.0.4 + * @since 2025/1/15 + */ +public final class CommandDispatcher { + + private static final Logger logger = LoggerFactory.getLogger(CommandDispatcher.class); + private static final CommandDispatcher INSTANCE = new CommandDispatcher(); + + // private-ctor + private CommandDispatcher() {} + + /** + * 最顶层指令缓存 + */ + private final Map commands = new ConcurrentHashMap<>(128); + + /** + * 指令注册 + * @param command 指令 + */ + public void register(Command command) { + commands.put(command.getName(), command); + } + + /** + * 指令反注册 + * @param command 指令 + */ + public void unregister(Command command) { + commands.remove(command.getName()); + } + + /** + * 处理输入的指令 + * @param input 指令 + */ + public void onCommand(String input) { + if (input == null || + input.isEmpty()) { + return; + } + + String[] args = input.split(" "); + String cmd = args[0]; + + Command command = commands.get(cmd); + if (command == null) { + logger.warn("未知指令: {}, 请输入 help 查看帮助!", cmd); + return; + } + if (!command.onCommand(splitArgs(args))) { + logger.error("指令执行出现了错误: {}", Arrays.toString(args)); + } + } + + /** + * 分割指令参数 + *
  • cmd x1 x2 => x1 x2 + * + * @param args 参数 + * @return 去除指令本身的参数部分 + */ + public static String[] splitArgs(String[] args) { + String[] newArgs = new String[args.length - 1]; + System.arraycopy(args, 1, newArgs, 0, args.length - 1); + return newArgs; + } + + /** + * 获取实例 + */ + public static CommandDispatcher getInstance() { + return INSTANCE; + } +} 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 new file mode 100644 index 0000000..cafc776 --- /dev/null +++ b/src/main/java/com/serliunx/ddns/support/command/target/HelpCommand.java @@ -0,0 +1,29 @@ +package com.serliunx.ddns.support.command.target; + +import com.serliunx.ddns.ManagerLite; +import com.serliunx.ddns.support.command.AbstractCommand; +import org.slf4j.Logger; + +import java.util.Arrays; + +/** + * 指令: help + * + * @author SerLiunx + * @version 1.0.0 + * @since 2025/1/15 + */ +public class HelpCommand extends AbstractCommand { + + private static final Logger log = ManagerLite.getLogger(); + + public HelpCommand() { + super("help", null, "查看帮助信息", "help cmd"); + } + + @Override + public boolean onCommand(String[] args) { + System.out.println(Arrays.toString(args)); + return true; + } +} \ No newline at end of file