添加自动命令表生成与清理,添加控制选项简写

- 添加使 MornyCoeur 携带自己的命令管理器
  - 使 Morny 在启动时可以自动向 Telegram 设定自己的命令表
    - 添加参数 --auto-cmd-list 用于开启这个行为
  - 使 Morny 可以在进行关闭清理时自动向 Telegram 删除命令表
    - 添加参数 --auto-cmd-remove 用于开启这个行为
- 为每个行为控制选项添加了其简写形式
This commit is contained in:
A.C.Sukazyo Eyre 2022-01-29 17:10:39 +08:00
parent 272ce7d606
commit 6dbe214476
Signed by: Eyre_S
GPG Key ID: EFB47D98FE082FAD
6 changed files with 116 additions and 28 deletions

View File

@ -1,6 +1,6 @@
## Core ## Core
VERSION = 0.5.0.0 VERSION = 0.5.0.1
# dependencies # dependencies

View File

@ -4,6 +4,6 @@ package cc.sukazyo.cono.morny;
* the final field that will be updated by gradle automatically. * the final field that will be updated by gradle automatically.
*/ */
public class GradleProjectConfigures { public class GradleProjectConfigures {
public static final String VERSION = "0.5.0.0"; public static final String VERSION = "0.5.0.1";
public static final long COMPILE_TIMESTAMP = 1643097522208L; public static final long COMPILE_TIMESTAMP = 1643447337882L;
} }

View File

@ -1,11 +1,13 @@
package cc.sukazyo.cono.morny; package cc.sukazyo.cono.morny;
import cc.sukazyo.cono.morny.bot.api.OnUpdate; import cc.sukazyo.cono.morny.bot.api.OnUpdate;
import cc.sukazyo.cono.morny.bot.command.MornyCommands;
import cc.sukazyo.cono.morny.bot.event.EventListeners; import cc.sukazyo.cono.morny.bot.event.EventListeners;
import cc.sukazyo.cono.morny.data.tracker.TrackerDataManager; import cc.sukazyo.cono.morny.data.tracker.TrackerDataManager;
import cc.sukazyo.untitled.telegram.api.extra.ExtraAction; import cc.sukazyo.untitled.telegram.api.extra.ExtraAction;
import com.pengrad.telegrambot.TelegramBot; import com.pengrad.telegrambot.TelegramBot;
import com.pengrad.telegrambot.model.DeleteMyCommands;
import com.pengrad.telegrambot.request.GetMe; import com.pengrad.telegrambot.request.GetMe;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@ -24,10 +26,13 @@ public class MornyCoeur {
/** 当前 Morny 的{@link MornyTrusted 信任验证机}实例 */ /** 当前 Morny 的{@link MornyTrusted 信任验证机}实例 */
private final MornyTrusted trusted; private final MornyTrusted trusted;
/** 当前 Morny 的 telegram 命令管理器 */
private final MornyCommands commandManager = new MornyCommands();
/** morny 的 bot 账户 */ /** morny 的 bot 账户 */
private final TelegramBot account; private final TelegramBot account;
private final ExtraAction extraActionInstance; private final ExtraAction extraActionInstance;
private final boolean isRemoveCommandListWhenExit;
/** /**
* morny bot 账户的用户名<br> * morny bot 账户的用户名<br>
* <br> * <br>
@ -67,10 +72,12 @@ public class MornyCoeur {
*/ */
private MornyCoeur ( private MornyCoeur (
@Nonnull String botKey, @Nullable String botUsername, @Nonnull String botKey, @Nullable String botUsername,
long master, long trustedChat, long latestEventTimestamp long master, long trustedChat, long latestEventTimestamp,
boolean isRemoveCommandListWhenExit
) { ) {
this.latestEventTimestamp = latestEventTimestamp; this.latestEventTimestamp = latestEventTimestamp;
this.isRemoveCommandListWhenExit = isRemoveCommandListWhenExit;
configureSafeExit(); configureSafeExit();
logger.info("args key:\n " + botKey); logger.info("args key:\n " + botKey);
@ -113,14 +120,24 @@ public class MornyCoeur {
*/ */
public static void main ( public static void main (
@Nonnull String botKey, @Nullable String botUsername, @Nonnull String botKey, @Nullable String botUsername,
long master, long trustedChat, long latestEventTimestamp long master, long trustedChat, long latestEventTimestamp,
boolean isAutomaticResetCommandList, boolean isRemoveCommandListWhenExit
) { ) {
if (INSTANCE == null) { if (INSTANCE == null) {
logger.info("System Starting"); logger.info("System Starting");
INSTANCE = new MornyCoeur(botKey, botUsername, master, trustedChat, latestEventTimestamp); INSTANCE = new MornyCoeur(
botKey, botUsername,
master, trustedChat,
latestEventTimestamp,
isRemoveCommandListWhenExit
);
TrackerDataManager.init(); TrackerDataManager.init();
EventListeners.registerAllListeners(); EventListeners.registerAllListeners();
INSTANCE.account.setUpdatesListener(OnUpdate::onNormalUpdate); INSTANCE.account.setUpdatesListener(OnUpdate::onNormalUpdate);
if (isAutomaticResetCommandList) {
logger.info("resetting telegram command list");
commandManager().automaticUpdateList();
}
logger.info("System start complete"); logger.info("System start complete");
return; return;
} }
@ -141,13 +158,17 @@ public class MornyCoeur {
private void exitCleanup () { private void exitCleanup () {
TrackerDataManager.DAEMON.interrupt(); TrackerDataManager.DAEMON.interrupt();
TrackerDataManager.trackingLock.lock(); TrackerDataManager.trackingLock.lock();
if (isRemoveCommandListWhenExit) {
extra().exec(new DeleteMyCommands());
logger.info("cleaned up command list.");
}
} }
/** /**
* 为程序在虚拟机上添加退出钩子 * 为程序在虚拟机上添加退出钩子
*/ */
private void configureSafeExit () { private void configureSafeExit () {
Runtime.getRuntime().addShutdownHook(new Thread(this::exitCleanup)); Runtime.getRuntime().addShutdownHook(new Thread(this::exitCleanup, "Exit-Cleaning"));
} }
/** /**
@ -229,6 +250,11 @@ public class MornyCoeur {
return INSTANCE.trusted; return INSTANCE.trusted;
} }
@Nonnull
public static MornyCommands commandManager () {
return INSTANCE.commandManager;
}
@Nonnull @Nonnull
public static ExtraAction extra () { public static ExtraAction extra () {
return INSTANCE.extraActionInstance; return INSTANCE.extraActionInstance;

View File

@ -49,6 +49,12 @@ public class ServerMain {
* {@code --outdated-block} 会使得 {@link MornyCoeur#latestEventTimestamp} * {@code --outdated-block} 会使得 {@link MornyCoeur#latestEventTimestamp}
* 赋值为程序启动的时间从而造成阻挡程序启动之前的消息事件处理效果 * 赋值为程序启动的时间从而造成阻挡程序启动之前的消息事件处理效果
* </li> * </li>
* <li>
* {@code --auto-cmd-list} 使 morny 在启动时自动依据程序本体更新登录 bot 的命令列表
* </li>
* <li>
* {@code --auto-cmd-remove} 使 morny 在关闭时自动依据程序本体删除 bot 的命令列表
* </li>
* </ul> * </ul>
* 除去选项之外第一个参数会被赋值为 bot telegram bot api token * 除去选项之外第一个参数会被赋值为 bot telegram bot api token
* 第二个参数会被赋值为 bot username 限定名其余的参数会被认定为无法理解<br> * 第二个参数会被赋值为 bot username 限定名其余的参数会被认定为无法理解<br>
@ -59,7 +65,7 @@ public class ServerMain {
* <s>但实际上这并不影响现在的使用选项赋值目前仍属于测试功能</s><br> * <s>但实际上这并不影响现在的使用选项赋值目前仍属于测试功能</s><br>
* <b>但请勿混用</b>这将使两个赋值出现混淆并<b>产生不可知的结果</b> * <b>但请勿混用</b>这将使两个赋值出现混淆并<b>产生不可知的结果</b>
* *
* @see MornyCoeur#main(String, String, long, long, long) * @see MornyCoeur#main
* @since 0.4.0.0 * @since 0.4.0.0
* @param args 参数组 * @param args 参数组
*/ */
@ -70,25 +76,27 @@ public class ServerMain {
boolean outdatedBlock = false; boolean outdatedBlock = false;
long master = 793274677L; long master = 793274677L;
long trustedChat = -1001541451710L; long trustedChat = -1001541451710L;
boolean autoCmdList = false;
boolean autoCmdRemove = false;
for (int i = 0; i < args.length; i++) { for (int i = 0; i < args.length; i++) {
if (args[i].startsWith("-")) { if (args[i].startsWith("-")) {
switch (args[i]) { switch (args[i]) {
case "--outdated-block" -> { case "--outdated-block", "-ob" -> {
outdatedBlock = true; outdatedBlock = true;
continue; continue;
} }
case "--no-hello" -> { case "--no-hello", "-hf" -> {
showWelcome = false; showWelcome = false;
continue; continue;
} }
case "--only-hello" -> { case "--only-hello", "-o" -> {
welcomeEchoMode = true; welcomeEchoMode = true;
continue; continue;
} }
case "--version" -> { case "--version", "-v" -> {
versionEchoMode = true; versionEchoMode = true;
continue; continue;
} }
@ -112,6 +120,14 @@ public class ServerMain {
trustedChat = Long.parseLong(args[i]); trustedChat = Long.parseLong(args[i]);
continue; continue;
} }
case "--auto-cmd-list", "-ca" -> {
autoCmdList = true;
continue;
}
case "--auto-cmd-remove", "-cr" -> {
autoCmdRemove = true;
continue;
}
} }
} else { } else {
@ -155,7 +171,12 @@ public class ServerMain {
if (welcomeEchoMode) return; if (welcomeEchoMode) return;
assert key != null; assert key != null;
MornyCoeur.main(key, username, master, trustedChat, outdatedBlock?System.currentTimeMillis():0); MornyCoeur.main(
key, username,
master, trustedChat,
outdatedBlock?System.currentTimeMillis():0,
autoCmdList, autoCmdRemove
);
} }

View File

@ -7,15 +7,19 @@ import cc.sukazyo.cono.morny.data.MornyJrrp;
import cc.sukazyo.cono.morny.data.TelegramStickers; import cc.sukazyo.cono.morny.data.TelegramStickers;
import cc.sukazyo.untitled.telegram.api.formatting.TGToString; import cc.sukazyo.untitled.telegram.api.formatting.TGToString;
import cc.sukazyo.untitled.util.telegram.object.InputCommand; import cc.sukazyo.untitled.util.telegram.object.InputCommand;
import com.pengrad.telegrambot.model.BotCommand;
import com.pengrad.telegrambot.model.Update; import com.pengrad.telegrambot.model.Update;
import com.pengrad.telegrambot.model.request.ParseMode; import com.pengrad.telegrambot.model.request.ParseMode;
import com.pengrad.telegrambot.request.SendMessage; import com.pengrad.telegrambot.request.SendMessage;
import com.pengrad.telegrambot.request.SendSticker; import com.pengrad.telegrambot.request.SendSticker;
import com.pengrad.telegrambot.request.SetMyCommands;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.HashMap; import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import static cc.sukazyo.cono.morny.Log.logger; import static cc.sukazyo.cono.morny.Log.logger;
@ -25,7 +29,7 @@ import static cc.sukazyo.untitled.util.telegram.formatting.MsgEscape.escapeHtml;
public class MornyCommands { public class MornyCommands {
private final Map<String, ITelegramCommand> commands = new HashMap<>(); private final Map<String, ITelegramCommand> commands = new LinkedHashMap<>();
private void pushCommandTo (@Nonnull String name, @Nonnull ITelegramCommand instance) { private void pushCommandTo (@Nonnull String name, @Nonnull ITelegramCommand instance) {
if (commands.containsKey(name)) { if (commands.containsKey(name)) {
@ -52,20 +56,18 @@ public class MornyCommands {
public MornyCommands () { public MornyCommands () {
register( register(
// simple commands register
new ON(), new ON(),
new Hello(), new Hello(),
new Exit(), new GetUsernameAndId(),
new EventHack(),
new Nbnhhsh(),
new Ip186Query.Ip(),
new Ip186Query.Whois(),
new SaveData(),
new Version(), new Version(),
new MornyRuntime(), new MornyRuntime(),
new Jrrp(), new Jrrp(),
new SaveData(), new Exit()
// rich commands register
new EventHack(),
new GetUsernameAndId(),
new Ip186Query.Ip(),
new Ip186Query.Whois(),
new Nbnhhsh()
); );
} }
@ -78,6 +80,43 @@ public class MornyCommands {
return nonCommandExecutable(event, command); return nonCommandExecutable(event, command);
} }
public void automaticUpdateList () {
BotCommand[] commandList = getCommandListTelegram();
MornyCoeur.extra().exec(new SetMyCommands(
commandList
));
logger.info("automatic updated telegram command list :\n" + commandListToString(commandList));
}
private String commandListToString (@Nonnull BotCommand[] list) {
StringBuilder builder = new StringBuilder();
for (BotCommand signal : list) {
builder.append(signal.command()).append(" - ").append(signal.description()).append("\n");
}
return builder.substring(0, builder.length()-1);
}
public BotCommand[] getCommandListTelegram () {
final List<BotCommand> telegramFormatListing = new ArrayList<>();
commands.forEach((regKey, command) -> {
if (regKey.equals(command.getName())) {
telegramFormatListing.add(formatTelegramCommandListLine(
command.getName(),
command.getParamRule(),
command.getDescription()
));
if (command.getAliases() != null) for (String alias : command.getAliases()) {
telegramFormatListing.add(formatTelegramCommandListLine(alias, "", ""));
}
}
});
return telegramFormatListing.toArray(BotCommand[]::new);
}
private BotCommand formatTelegramCommandListLine (@Nonnull String commandName, @Nonnull String paramRule, @Nonnull String intro) {
return new BotCommand(commandName, "".equals(paramRule) ? (intro) : (paramRule+" - "+intro));
}
private boolean nonCommandExecutable (Update event, InputCommand command) { private boolean nonCommandExecutable (Update event, InputCommand command) {
if (command.getTarget() == null) return false; // 无法解析的命令转交事件链后代处理 if (command.getTarget() == null) return false; // 无法解析的命令转交事件链后代处理
else { // 无法解析的显式命令格式报错找不到命令 else { // 无法解析的显式命令格式报错找不到命令
@ -90,6 +129,11 @@ public class MornyCommands {
} }
} }
/// /// /// /// /// /// /// /// ///
///
/// Old Simple Command Block
///
private static class ON implements ITelegramCommand { private static class ON implements ITelegramCommand {
@Nonnull @Override public String getName () { return "/on"; } @Nonnull @Override public String getName () { return "/on"; }
@Nullable @Nullable

View File

@ -2,7 +2,6 @@ package cc.sukazyo.cono.morny.bot.event;
import cc.sukazyo.cono.morny.MornyCoeur; import cc.sukazyo.cono.morny.MornyCoeur;
import cc.sukazyo.cono.morny.bot.api.EventListener; import cc.sukazyo.cono.morny.bot.api.EventListener;
import cc.sukazyo.cono.morny.bot.command.MornyCommands;
import cc.sukazyo.untitled.util.telegram.object.InputCommand; import cc.sukazyo.untitled.util.telegram.object.InputCommand;
import com.pengrad.telegrambot.model.Update; import com.pengrad.telegrambot.model.Update;
@ -11,8 +10,6 @@ import javax.annotation.Nonnull;
public class OnTelegramCommand extends EventListener { public class OnTelegramCommand extends EventListener {
private final MornyCommands commandManager = new MornyCommands();
@Override @Override
public boolean onMessage (@Nonnull Update event) { public boolean onMessage (@Nonnull Update event) {
if (event.message().text() == null) { if (event.message().text() == null) {
@ -22,7 +19,7 @@ public class OnTelegramCommand extends EventListener {
if (command.getTarget() != null && !MornyCoeur.getUsername().equals(command.getTarget())) { if (command.getTarget() != null && !MornyCoeur.getUsername().equals(command.getTarget())) {
return true; // 检测到命令并非针对 morny退出整个事件处理链 return true; // 检测到命令并非针对 morny退出整个事件处理链
} }
return commandManager.execute(command, event); // 转交命令管理器执行命令 return MornyCoeur.commandManager().execute(command, event); // 转交命令管理器执行命令
} }
} }