分离程序入口与主程序启动,优化参数处理,添加过期事件抑制功能

This commit is contained in:
A.C.Sukazyo Eyre 2021-12-08 12:43:12 +08:00
parent b32b465a12
commit d65f2d9f24
Signed by: Eyre_S
GPG Key ID: EFB47D98FE082FAD
7 changed files with 197 additions and 53 deletions

View File

@ -7,7 +7,7 @@ plugins {
}
group 'cc.sukazyo'
version '0.3.4.4'
version '0.4.0.0'
project.ext.archiveBaseName = 'Coeur_Morny_Cono'
project.ext.artifactId = 'morny-coeur'
mainClassName = 'cc.sukazyo.cono.morny.MornyCoeur'

View File

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

View File

@ -7,12 +7,7 @@ import com.pengrad.telegrambot.TelegramBot;
import com.pengrad.telegrambot.request.GetMe;
import javax.annotation.Nonnull;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import javax.annotation.Nullable;
import static cc.sukazyo.cono.morny.Logger.logger;
@ -28,61 +23,45 @@ public class MornyCoeur {
/**
* morny bot 账户的用户名<br>
* <br>
* 出于技术限制这个字段目前是写死的
* 这个字段将会在登陆成功后赋值为登录到的 bot username
* 它应该是和 {@link #account} username 同步的<br>
* <br>
* 如果在登陆之前就定义了此字段则登陆代码会验证登陆的 bot username
* 是否与定义的 username 符合如果不符合则会报错
*/
public static String username;
private static String username;
/**
* morny 的事件忽略前缀时间<br>
* <br>
* {@link cc.sukazyo.cono.morny.bot.event.OnUpdateTimestampOffsetLock}
* 会根据这里定义的时间戳取消掉比此时间更早的事件链
*/
public static long latestEventTimestamp;
/**
* 程序入口<br>
* <br>
* 会从命令行参数取得初始化数据并初始化程序和bot<br>
* <br>
* - 第一个参数({@code args[0]})必序传递值为 telegram-bot api-token<br>
* - 第二个参数可选 {@code --no-hello} {@code --only-hello}
* 前者表示不输出{@link MornyHello#MORNY_PREVIEW_IMAGE_ASCII 欢迎标语}
* 后者表示只输出{@link MornyHello#MORNY_PREVIEW_IMAGE_ASCII 欢迎标语}而不运行程序逻辑<br>
* <br>
* 或者在第一个参数处使用 {@code --version} 来输出当前程序的版本信息
* bot 启动入口执行 bot 初始化
*
* @param args 程序命令行参数
* @param botKey bot telegram bot api token
* @param botUsername bot username 限定如果为 null 则表示不限定
* 如果指定则登录时会检查所登陆的 bot 的用户名是否与此相等
* @param latestEventTimestamp 事件处理器会处理事件的最早时间戳
* 只有限定的 message 事件会受此影响
* 单位为毫秒
*/
public static void main (@Nonnull String[] args) {
public static void main (@Nonnull String botKey, @Nullable String botUsername, long latestEventTimestamp) {
if ("--version".equals(args[0])) {
logger.info(String.format("""
Morny Cono Version
- version :
%s
- md5hash :
%s
- co.time :
%d
%s [UTC]""",
MornySystem.VERSION,
MornySystem.getJarMd5(),
GradleProjectConfigures.COMPILE_TIMESTAMP,
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss:SSS").format(LocalDateTime.ofInstant(
Instant.ofEpochMilli(GradleProjectConfigures.COMPILE_TIMESTAMP),
ZoneId.ofOffset("UTC", ZoneOffset.UTC)))
));
return;
}
MornyCoeur.latestEventTimestamp = latestEventTimestamp;
if (!(args.length > 1 && "--no-hello".equals(args[1])))
logger.info(MornyHello.MORNY_PREVIEW_IMAGE_ASCII);
if (args.length > 1 && "--only-hello".equals(args[1]))
return;
logger.info("System Starting");
configureSafeExit();
logger.info("args key:\n " + args[0]);
if (args.length > 2) {
username = args[2];
logger.info("login as:\n " + args[2]);
logger.info("args key:\n " + botKey);
if (botUsername != null) {
logger.info("login as:\n " + botUsername);
}
try { account = login(args[0]); }
try { account = login(botKey); }
catch (Exception e) { logger.error("Cannot login to bot/api. :\n " + e.getMessage()); System.exit(-1); }
logger.info("Bot login succeed.");
@ -128,7 +107,7 @@ public class MornyCoeur {
if (i != 1) logger.info("retrying...");
try {
final String username = account.execute(new GetMe()).user().username();
if (username != null && !MornyCoeur.username.equals(username))
if (MornyCoeur.username != null && !MornyCoeur.username.equals(username))
throw new RuntimeException("Required the bot @" + MornyCoeur.username + " but @" + username + " logged in!");
else MornyCoeur.username = username;
logger.info("Succeed login to @" + username);
@ -150,4 +129,13 @@ public class MornyCoeur {
return account;
}
/**
* 获取登录 bot username
*
* @return {@link #username MornyCoeur.username}
*/
public static String getUsername () {
return username;
}
}

View File

@ -0,0 +1,139 @@
package cc.sukazyo.cono.morny;
import javax.annotation.Nonnull;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import static cc.sukazyo.cono.morny.Logger.logger;
/**
* 程序启动入口<br>
* <br>
* 会处理程序传入的参数和选项等数据并执行对应的启动方式<br>
* <br>
* - 第一个参数({@code args[0]})必序传递值为 telegram-bot api-token<br>
* - 第二个参数可选 {@code --no-hello} {@code --only-hello}
* 前者表示不输出{@link MornyHello#MORNY_PREVIEW_IMAGE_ASCII 欢迎标语}
* 后者表示只输出{@link MornyHello#MORNY_PREVIEW_IMAGE_ASCII 欢迎标语}而不运行程序逻辑<br>
* <br>
* 或者在第一个参数处使用 {@code --version} 来输出当前程序的版本信息
*
* @since 0.4.0.0
*/
public class ServerMain {
private static boolean versionEchoMode = false;
private static boolean welcomeEchoMode = false;
private static boolean showWelcome = true;
/**
* 程序入口也是参数处理器<br>
* <br>
* {@code -} 开头的参数会被解析为选项<br>
* <br>
* 支持以下选项
* <ul>
* <li>
* {@code --version} 只输出版本信息不运行主程序此参数会导致其它所有参数失效优先级最高
* </li>
* <li>
* {@code --only-hello} 只输出欢迎字符画({@link MornyHello})不运行主程序
* 不要同时使用 {@code --no-hello}原因见下
* </li>
* <li>
* {@code --no-hello} 不在主程序启动时输出用于欢迎消息的字符画
* {@code --only-hello} 参数不兼容 会导致程序完全没有任何输出
* </li>
* <li>
* {@code --outdated-block} 会使得 {@link MornyCoeur#latestEventTimestamp}
* 赋值为程序启动的时间从而造成阻挡程序启动之前的消息事件处理效果
* </li>
* </ul>
* 除去选项之外第一个参数会被赋值为 bot telegram bot api token
* 第二个参数会被赋值为 bot username 限定名其余的参数会被认定为无法理解
*
* @see MornyCoeur#main(String, String, long)
* @since 0.4.0.0
* @param args 参数组
*/
public static void main (@Nonnull String[] args) {
String key = null;
String username = null;
boolean outdatedBlock = false;
for (String arg : args) {
if (arg.startsWith("-")) {
switch (arg) {
case "--outdated-block" -> {
outdatedBlock = true;
continue;
}
case "--no-hello" -> {
showWelcome = false;
continue;
}
case "--only-hello" -> {
welcomeEchoMode = true;
continue;
}
case "--version" -> {
versionEchoMode = true;
continue;
}
}
} else {
if (key == null) {
key = arg;
continue;
}
if (username == null) {
username = arg;
continue;
}
}
logger.warn("Can't understand arg to some meaning :\n " + arg);
}
if (versionEchoMode) {
logger.info(String.format("""
Morny Cono Version
- version :
%s
- md5hash :
%s
- co.time :
%d
%s [UTC]""",
MornySystem.VERSION,
MornySystem.getJarMd5(),
GradleProjectConfigures.COMPILE_TIMESTAMP,
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss:SSS").format(LocalDateTime.ofInstant(
Instant.ofEpochMilli(GradleProjectConfigures.COMPILE_TIMESTAMP),
ZoneId.ofOffset("UTC", ZoneOffset.UTC)))
));
return;
}
if (showWelcome) logger.info(MornyHello.MORNY_PREVIEW_IMAGE_ASCII);
if (welcomeEchoMode) return;
assert key != null;
MornyCoeur.main(key, username, outdatedBlock?System.currentTimeMillis():0);
}
}

View File

@ -7,10 +7,12 @@ public class EventListeners {
public static final OnCommandExecute COMMANDS_LISTENER = new OnCommandExecute();
public static final OnActivityRecord ACTIVITY_RECORDER = new OnActivityRecord();
public static final OnUserSlashAction USER_SLASH_ACTION = new OnUserSlashAction();
public static final OnUpdateTimestampOffsetLock UPDATE_TIMESTAMP_OFFSET_LOCK = new OnUpdateTimestampOffsetLock();
public static void registerAllListeners () {
EventListenerManager.addListener(
ACTIVITY_RECORDER,
UPDATE_TIMESTAMP_OFFSET_LOCK,
COMMANDS_LISTENER,
USER_SLASH_ACTION
);

View File

@ -35,7 +35,7 @@ public class OnCommandExecute extends EventListener {
return false; // 检测到无消息文本忽略掉命令处理
}
final InputCommand command = new InputCommand(event.message().text());
if (command.getTarget() != null && !MornyCoeur.username.equals(command.getTarget())) {
if (command.getTarget() != null && !MornyCoeur.getUsername().equals(command.getTarget())) {
return true; // 检测到命令并非针对 morny退出整个事件处理链
}
switch (command.getCommand()) {

View File

@ -0,0 +1,15 @@
package cc.sukazyo.cono.morny.bot.event;
import cc.sukazyo.cono.morny.MornyCoeur;
import cc.sukazyo.cono.morny.bot.api.EventListener;
import com.pengrad.telegrambot.model.Update;
import org.jetbrains.annotations.NotNull;
public class OnUpdateTimestampOffsetLock extends EventListener {
@Override
public boolean onMessage (@NotNull Update update) {
return update.message().date() < MornyCoeur.latestEventTimestamp*1000;
}
}