feat: 新增指令调度器.

This commit is contained in:
2025-01-15 21:49:11 +08:00
parent b3c79f49a0
commit 1bcdabc595
5 changed files with 247 additions and 11 deletions

View File

@@ -6,13 +6,18 @@ import com.serliunx.ddns.config.PropertiesConfiguration;
import com.serliunx.ddns.constant.SystemConstants; import com.serliunx.ddns.constant.SystemConstants;
import com.serliunx.ddns.core.context.FileInstanceContext; import com.serliunx.ddns.core.context.FileInstanceContext;
import com.serliunx.ddns.core.context.MultipleSourceInstanceContext; import com.serliunx.ddns.core.context.MultipleSourceInstanceContext;
import com.serliunx.ddns.support.InstanceContextHolder;
import com.serliunx.ddns.support.SystemInitializer; 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 com.serliunx.ddns.support.log.JLineAdaptAppender;
import org.jline.reader.LineReader; import org.jline.reader.LineReader;
import org.jline.reader.LineReaderBuilder; import org.jline.reader.LineReaderBuilder;
import org.jline.reader.impl.history.DefaultHistory; import org.jline.reader.impl.history.DefaultHistory;
import org.jline.terminal.Terminal; import org.jline.terminal.Terminal;
import org.jline.terminal.TerminalBuilder; import org.jline.terminal.TerminalBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException; import java.io.IOException;
@@ -25,6 +30,11 @@ import java.io.IOException;
*/ */
public final class ManagerLite { 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 SystemInitializer systemInitializer;
/**
* 指令调度
*/
private static CommandDispatcher commandDispatcher;
/**
* 获取默认的日志输出
*/
public static Logger getLogger() {
return DEFAULT_LOGGER;
}
public static void main(String[] args) { public static void main(String[] args) {
// 配置初始化 // 配置初始化
initConfiguration(args); initConfiguration(args);
@@ -49,6 +69,9 @@ public final class ManagerLite {
// 系统初始化 // 系统初始化
initSystem(); initSystem();
// 指令初始化
initCommands();
Terminal terminal; Terminal terminal;
try { try {
terminal = TerminalBuilder.builder() terminal = TerminalBuilder.builder()
@@ -67,30 +90,35 @@ public final class ManagerLite {
JLineAdaptAppender.setLineReader(lineReader); JLineAdaptAppender.setLineReader(lineReader);
String prompt = "client> "; final String prompt = "client> ";
InstanceContextHolder.setAdditional("command-process");
while (true) { while (true) {
// 该方法会阻塞,直到用户敲回车 // 该方法会阻塞,直到用户敲回车
try { try {
String cmd = lineReader.readLine(prompt); String cmd = lineReader.readLine(prompt);
// 当用户输入 exit 或 quit,就退出循环 // 当用户输入 exit就退出循环
if ("exit".equalsIgnoreCase(cmd)) { if ("exit".equalsIgnoreCase(cmd)) {
break; break;
} }
// 在这里可以对用户输入做进一步处理 commandDispatcher.onCommand(cmd);
terminal.flush(); terminal.flush();
} catch (Exception e) { } catch (Exception e) {
System.exit(0); break;
} }
} }
try {
System.exit(0); System.exit(0);
terminal.close();
} catch (IOException e) {
throw new RuntimeException(e);
} }
/**
* 指令初始化
*/
private static void initCommands() {
commandDispatcher = CommandDispatcher.getInstance();
// help
commandDispatcher.register(new HelpCommand());
} }
/** /**

View File

@@ -0,0 +1,46 @@
package com.serliunx.ddns.support.command;
import java.util.List;
/**
* 指令的抽象实现
* <li> 实现公共逻辑及定义具体逻辑
*
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
* @version 1.0.4
* @since 2025/1/15
*/
public abstract class AbstractCommand implements Command {
private final String name;
private final List<Command> subCommands;
private final String description;
private final String usage;
public AbstractCommand(String name, List<Command> 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<Command> getSubCommands() {
return subCommands;
}
@Override
public String getDescription() {
return description;
}
@Override
public String getUsage() {
return usage;
}
}

View File

@@ -0,0 +1,44 @@
package com.serliunx.ddns.support.command;
import java.util.List;
/**
* 指令接口定义
*
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
* @version 1.0.4
* @since 2025/1/15
*/
public interface Command {
/**
* 指令执行逻辑
*
* @param args 当前指令参数
* @return 成功执行返回真, 否则返回假. (目前没影响)
*/
boolean onCommand(String[] args);
/**
* 获取指令名称
*/
String getName();
/**
* 获取子命令
* <li> 例: cmd c1 c2, 此时 c1为cmd的子命令
*
* @return 子命令
*/
List<Command> getSubCommands();
/**
* 获取该指令的描述
*/
String getDescription();
/**
* 获取该指令的用法
*/
String getUsage();
}

View File

@@ -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 <a href="mailto:serliunx@yeah.net">SerLiunx</a>
* @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<String, Command> 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));
}
}
/**
* 分割指令参数
* <li> 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;
}
}

View File

@@ -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 <a href="mailto:serliunx@yeah.net">SerLiunx</a>
* @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;
}
}