feat: 控制台输出样式调整、新增instance指令.

This commit is contained in:
2025-02-04 12:16:43 +08:00
parent 4a05256c59
commit 2cd4eeabd2
10 changed files with 179 additions and 12 deletions

View File

@@ -16,6 +16,7 @@ import com.serliunx.ddns.support.command.target.HelpCommand;
import com.serliunx.ddns.support.command.target.ReloadCommand; import com.serliunx.ddns.support.command.target.ReloadCommand;
import com.serliunx.ddns.support.command.target.StopCommand; import com.serliunx.ddns.support.command.target.StopCommand;
import com.serliunx.ddns.support.command.target.config.ConfigCommand; import com.serliunx.ddns.support.command.target.config.ConfigCommand;
import com.serliunx.ddns.support.command.target.instance.InstanceCommand;
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;
@@ -143,6 +144,8 @@ public final class ManagerLite {
commandDispatcher.register(new ConfigCommand(configuration)); commandDispatcher.register(new ConfigCommand(configuration));
// stop // stop
commandDispatcher.register(new StopCommand()); commandDispatcher.register(new StopCommand());
// instance
commandDispatcher.register(new InstanceCommand(systemInitializer));
} }
/** /**

View File

@@ -109,7 +109,7 @@ public abstract class AbstractInstanceContext implements InstanceContext, Multip
@Override @Override
public Set<Instance> getInstances() { public Set<Instance> getInstances() {
return instanceMap == null ? Collections.emptySet() : new HashSet<>(instanceMap.values()); return instanceMap == null ? Collections.emptySet() : new LinkedHashSet<>(instanceMap.values());
} }
@Override @Override

View File

@@ -0,0 +1,66 @@
package com.serliunx.ddns.support;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* 控制台样式助手
*
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
* @version 1.0.4
* @since 2025/2/4
*/
public final class ConsoleStyleHelper {
/**
* ANSI 控制台经典样式编码映射表
*/
private static final Map<String, String> CLASSIC_STYLE_MAP = new HashMap<>();
static {
// 格式
CLASSIC_STYLE_MAP.put("&r", "\033[0m"); // 重置
CLASSIC_STYLE_MAP.put("&l", "\033[1m"); // 加粗或高亮
// 颜色
CLASSIC_STYLE_MAP.put("&0", "\033[30m"); // 黑色
CLASSIC_STYLE_MAP.put("&1", "\033[31m"); // 红色
CLASSIC_STYLE_MAP.put("&2", "\033[32m"); // 绿色
CLASSIC_STYLE_MAP.put("&3", "\033[33m"); // 黄色
CLASSIC_STYLE_MAP.put("&4", "\033[34m"); // 蓝色
CLASSIC_STYLE_MAP.put("&5", "\033[35m"); // 品红
CLASSIC_STYLE_MAP.put("&6", "\033[36m"); // 青色
CLASSIC_STYLE_MAP.put("&7", "\033[37m"); // 白色
}
/**
* 格式化输出, 支持颜色代码
*
* @param format 格式
* @param args 参数
*/
public static void coloredPrintf(String format, final Object... args) {
if (!format.endsWith("%n")) {
format = format + "%n";
}
if (!format.endsWith("&r")) {
format = format + "&r";
}
System.out.printf(replaceStyleCode(format), args);
}
/**
* 替换样式代码
*
* @param original 原始文本
* @return 替换后的文本
*/
private static String replaceStyleCode(String original) {
Set<Map.Entry<String, String>> entries = CLASSIC_STYLE_MAP.entrySet();
for (Map.Entry<String, String> entry : entries) {
original = original.replace(entry.getKey(), entry.getValue());
}
return original;
}
}

View File

@@ -10,6 +10,8 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static com.serliunx.ddns.support.ConsoleStyleHelper.coloredPrintf;
/** /**
* 指令的抽象实现 * 指令的抽象实现
* <li> 实现公共逻辑及定义具体逻辑 * <li> 实现公共逻辑及定义具体逻辑
@@ -68,8 +70,10 @@ public abstract class AbstractCommand implements Command {
@Override @Override
public boolean onCommand(String[] args) { public boolean onCommand(String[] args) {
if (!hasArgs(args) || if (!hasArgs(args) ||
args.length < 2) { args.length < 1) {
log.warn("用法 => {}", getUsage()); System.out.println();
coloredPrintf("&2用法 =>&r &6%s", getUsage());
System.out.println();
return true; return true;
} }

View File

@@ -7,6 +7,8 @@ import java.util.Arrays;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import static com.serliunx.ddns.support.ConsoleStyleHelper.coloredPrintf;
/** /**
* 指令调度器 * 指令调度器
* *
@@ -70,11 +72,13 @@ public final class CommandDispatcher {
Command command = commands.get(cmd); Command command = commands.get(cmd);
if (command == null) { if (command == null) {
logger.warn("未知指令: {}, 请输入 help 查看帮助!", cmd); System.out.println();
coloredPrintf("&1未知指令&r: &2%s&r, &1请输入 &3help&r &1查看帮助!", cmd);
System.out.println();
return; return;
} }
if (!command.onCommand(splitArgs(args))) { if (!command.onCommand(splitArgs(args))) {
logger.error("指令执行出现了错误: {}", Arrays.toString(args)); coloredPrintf("&1指令执行出现了错误:&r &5%s", Arrays.toString(args));
} }
} }

View File

@@ -11,6 +11,8 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import static com.serliunx.ddns.support.ConsoleStyleHelper.coloredPrintf;
/** /**
* 指令: help * 指令: help
* *
@@ -31,29 +33,32 @@ public class HelpCommand extends AbstractCommand {
if (hasArgs(args)) { if (hasArgs(args)) {
final String cmd = args[0]; final String cmd = args[0];
final Command command = commands.get(cmd); final Command command = commands.get(cmd);
System.out.println();
if (command == null) { if (command == null) {
System.out.printf("无法找到指令 %s 的相关信息, 请使用 help 查看可用的指令及帮助!%n", cmd); coloredPrintf("&1无法找到指令 %s 的相关信息, 请使用 help 查看可用的指令及帮助!%n", cmd);
} else { } else {
List<Command> subCommands = command.getSubCommands(); List<Command> subCommands = command.getSubCommands();
if (subCommands == null || if (subCommands == null ||
subCommands.isEmpty()) { subCommands.isEmpty()) {
System.out.printf("指令:%s - %s - %s%n", cmd, command.getDescription(), command.getUsage()); coloredPrintf("&2%s&r - &6%s&r - &5%s%n", cmd, command.getDescription(), command.getUsage());
} else { } else {
subCommands.forEach(c -> { subCommands.forEach(c -> {
System.out.printf("%s - %s - %s%n", c.getName(), c.getDescription(), c.getUsage()); coloredPrintf("&2%s&r - &6%s&r - &5%s%n", c.getName(), c.getDescription(), c.getUsage());
}); });
} }
} }
System.out.println();
} else { } else {
System.out.println();
commands.forEach((k, v) -> { commands.forEach((k, v) -> {
// 忽略 help 自身 // 忽略 help 自身
if (k.equals(getName())) { if (k.equals(getName())) {
return; return;
} }
System.out.printf("%s - %s - %s%n", k, v.getDescription(), v.getUsage()); coloredPrintf("&2%s&r\t - &6%s&r - &5%s%n", k, v.getDescription(), v.getUsage());
}); });
System.out.println(); System.out.println();
System.out.println("使用 help <指令> 来查看更详细的帮助信息."); coloredPrintf("&6&l使用 help <指令> 来查看更详细的帮助信息.");
} }
return true; return true;
} }

View File

@@ -8,6 +8,8 @@ import org.jline.reader.ParsedLine;
import java.util.List; import java.util.List;
import static com.serliunx.ddns.support.ConsoleStyleHelper.coloredPrintf;
/** /**
* 指令: config get * 指令: config get
* *
@@ -31,7 +33,9 @@ public final class ConfigGetCommand extends AbstractCommand {
public boolean onCommand(String[] args) { public boolean onCommand(String[] args) {
if (!hasArgs(args) || if (!hasArgs(args) ||
args.length < 1) { args.length < 1) {
log.warn("用法 => {}", getUsage()); System.out.println();
coloredPrintf("&2用法 =>&r &6%s", getUsage());
System.out.println();
return true; return true;
} }
System.out.println(configuration.getString(args[0])); System.out.println(configuration.getString(args[0]));

View File

@@ -8,6 +8,8 @@ import org.jline.reader.ParsedLine;
import java.util.List; import java.util.List;
import static com.serliunx.ddns.support.ConsoleStyleHelper.coloredPrintf;
/** /**
* 指令: config set * 指令: config set
* *
@@ -31,7 +33,9 @@ public final class ConfigSetCommand extends AbstractCommand {
public boolean onCommand(String[] args) { public boolean onCommand(String[] args) {
if (!hasArgs(args) || if (!hasArgs(args) ||
args.length < 2) { args.length < 2) {
log.warn("用法 => {}", getUsage()); System.out.println();
coloredPrintf("&2用法 =>&r &6%s", getUsage());
System.out.println();
return true; return true;
} }
final String target = args[0]; final String target = args[0];

View File

@@ -0,0 +1,22 @@
package com.serliunx.ddns.support.command.target.instance;
import com.serliunx.ddns.support.SystemInitializer;
import com.serliunx.ddns.support.command.AbstractCommand;
import java.util.ArrayList;
/**
* 指令: instance
*
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
* @version 1.0.4
* @since 2025/2/4
*/
public final class InstanceCommand extends AbstractCommand {
public InstanceCommand(SystemInitializer systemInitializer) {
super("instance", new ArrayList<>(), "实例相关指令", "instance list/add/...");
// 子命令: list
addSubCommand(new InstanceListCommand(systemInitializer));
}
}

View File

@@ -0,0 +1,55 @@
package com.serliunx.ddns.support.command.target.instance;
import com.serliunx.ddns.core.instance.Instance;
import com.serliunx.ddns.support.Assert;
import com.serliunx.ddns.support.ConsoleStyleHelper;
import com.serliunx.ddns.support.SystemInitializer;
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.Set;
/**
* 指令: instance list
*
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
* @version 1.0.4
* @since 2025/2/4
*/
public final class InstanceListCommand extends AbstractCommand {
private final SystemInitializer systemInitializer;
public InstanceListCommand(SystemInitializer systemInitializer) {
super("list", new ArrayList<>(), "列出所有实例", "instance list");
Assert.notNull(systemInitializer);
this.systemInitializer = systemInitializer;
}
@Override
public boolean onCommand(String[] args) {
Set<Instance> instances = systemInitializer.getInstances();
System.out.println();
instances.forEach(i -> {
ConsoleStyleHelper.coloredPrintf("&2%s&r(&3%s&r)", i.getName(), i.getType());
});
System.out.println();
return true;
}
@Override
public List<String> getArgs() {
return null;
}
@Override
public void onComplete(LineReader reader, ParsedLine line, int index, List<Candidate> candidates) {
//do nothing for list
}
}