diff --git a/build.gradle b/build.gradle index 2d6ec16..f3d53fd 100644 --- a/build.gradle +++ b/build.gradle @@ -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' diff --git a/src/main/java/cc/sukazyo/cono/morny/GradleProjectConfigures.java b/src/main/java/cc/sukazyo/cono/morny/GradleProjectConfigures.java index 87c1e24..a361cc3 100644 --- a/src/main/java/cc/sukazyo/cono/morny/GradleProjectConfigures.java +++ b/src/main/java/cc/sukazyo/cono/morny/GradleProjectConfigures.java @@ -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; } diff --git a/src/main/java/cc/sukazyo/cono/morny/MornyCoeur.java b/src/main/java/cc/sukazyo/cono/morny/MornyCoeur.java index ed1556a..4dc90bf 100644 --- a/src/main/java/cc/sukazyo/cono/morny/MornyCoeur.java +++ b/src/main/java/cc/sukazyo/cono/morny/MornyCoeur.java @@ -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 账户的用户名
*
- * 出于技术限制,这个字段目前是写死的 + * 这个字段将会在登陆成功后赋值为登录到的 bot 的 username。 + * 它应该是和 {@link #account} 的 username 同步的
+ *
+ * 如果在登陆之前就定义了此字段,则登陆代码会验证登陆的 bot 的 username + * 是否与定义的 username 符合。如果不符合则会报错。 */ - public static String username; + private static String username; + /** + * morny 的事件忽略前缀时间
+ *
+ * {@link cc.sukazyo.cono.morny.bot.event.OnUpdateTimestampOffsetLock} + * 会根据这里定义的时间戳取消掉比此时间更早的事件链 + */ + public static long latestEventTimestamp; /** - * 程序入口
- *
- * 会从命令行参数取得初始化数据并初始化程序和bot
- *
- * - 第一个参数({@code args[0]})必序传递,值为 telegram-bot 的 api-token
- * - 第二个参数可选 {@code --no-hello} 和 {@code --only-hello}, - * 前者表示不输出{@link MornyHello#MORNY_PREVIEW_IMAGE_ASCII 欢迎标语}, - * 后者表示只输出{@link MornyHello#MORNY_PREVIEW_IMAGE_ASCII 欢迎标语}而不运行程序逻辑
- *
- * 或者,在第一个参数处使用 {@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; + } + } diff --git a/src/main/java/cc/sukazyo/cono/morny/ServerMain.java b/src/main/java/cc/sukazyo/cono/morny/ServerMain.java new file mode 100644 index 0000000..49074d0 --- /dev/null +++ b/src/main/java/cc/sukazyo/cono/morny/ServerMain.java @@ -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; + +/** + * 程序启动入口
+ *
+ * 会处理程序传入的参数和选项等数据,并执行对应的启动方式
+ *
+ * - 第一个参数({@code args[0]})必序传递,值为 telegram-bot 的 api-token
+ * - 第二个参数可选 {@code --no-hello} 和 {@code --only-hello}, + * 前者表示不输出{@link MornyHello#MORNY_PREVIEW_IMAGE_ASCII 欢迎标语}, + * 后者表示只输出{@link MornyHello#MORNY_PREVIEW_IMAGE_ASCII 欢迎标语}而不运行程序逻辑
+ *
+ * 或者,在第一个参数处使用 {@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; + + /** + * 程序入口,也是参数处理器
+ *
+ * 以 {@code -} 开头的参数会被解析为选项
+ *
+ * 支持以下选项 + * + * 除去选项之外,第一个参数会被赋值为 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); + + } + +} diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/event/EventListeners.java b/src/main/java/cc/sukazyo/cono/morny/bot/event/EventListeners.java index 8359fef..8bb693b 100644 --- a/src/main/java/cc/sukazyo/cono/morny/bot/event/EventListeners.java +++ b/src/main/java/cc/sukazyo/cono/morny/bot/event/EventListeners.java @@ -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 ); diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/event/OnCommandExecute.java b/src/main/java/cc/sukazyo/cono/morny/bot/event/OnCommandExecute.java index 1db0756..012c56a 100644 --- a/src/main/java/cc/sukazyo/cono/morny/bot/event/OnCommandExecute.java +++ b/src/main/java/cc/sukazyo/cono/morny/bot/event/OnCommandExecute.java @@ -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()) { diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/event/OnUpdateTimestampOffsetLock.java b/src/main/java/cc/sukazyo/cono/morny/bot/event/OnUpdateTimestampOffsetLock.java new file mode 100644 index 0000000..2ad2fd4 --- /dev/null +++ b/src/main/java/cc/sukazyo/cono/morny/bot/event/OnUpdateTimestampOffsetLock.java @@ -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; + } + +}