diff --git a/gradle.properties b/gradle.properties index 38fb156..a3de3a3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ ## Core -VERSION = 0.4.2.6 +VERSION = 0.4.2.7 # dependencies diff --git a/src/main/java/cc/sukazyo/cono/morny/GradleProjectConfigures.java b/src/main/java/cc/sukazyo/cono/morny/GradleProjectConfigures.java index 5b30b66..f7af85d 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.4.2.6"; - public static final long COMPILE_TIMESTAMP = 1640065256004L; + public static final String VERSION = "0.4.2.7"; + public static final long COMPILE_TIMESTAMP = 1640104964102L; } diff --git a/src/main/java/cc/sukazyo/cono/morny/MornyCoeur.java b/src/main/java/cc/sukazyo/cono/morny/MornyCoeur.java index c6fdf0d..06d7944 100644 --- a/src/main/java/cc/sukazyo/cono/morny/MornyCoeur.java +++ b/src/main/java/cc/sukazyo/cono/morny/MornyCoeur.java @@ -17,8 +17,14 @@ import static cc.sukazyo.cono.morny.Log.logger; */ public class MornyCoeur { + /** 当前程序的 Morny Coeur 实例 */ + private static MornyCoeur INSTANCE; + + /** 当前 Morny 的{@link MornyTrusted 信任验证机}实例 */ + private final MornyTrusted trusted; + /** morny 的 bot 账户 */ - private static TelegramBot account; + private final TelegramBot account; /** * morny 的 bot 账户的用户名
*
@@ -28,36 +34,40 @@ public class MornyCoeur { * 如果在登陆之前就定义了此字段,则登陆代码会验证登陆的 bot 的 username * 是否与定义的 username 符合。如果不符合则会报错。 */ - private static String username; + private final String username; /** * morny 的事件忽略前缀时间
*
* {@link cc.sukazyo.cono.morny.bot.event.OnUpdateTimestampOffsetLock} * 会根据这里定义的时间戳取消掉比此时间更早的事件链 */ - public static long latestEventTimestamp; + public long latestEventTimestamp; /** * morny 主程序启动时间
* 用于统计数据 */ public static final long coeurStartTimestamp = System.currentTimeMillis(); + private record LogInResult(TelegramBot account, String username) { } + /** - * bot 启动入口,执行 bot 初始化 + * 执行 bot 初始化 * * @param botKey bot 的 telegram bot api token * @param botUsername bot 的 username 限定。如果为 null 则表示不限定, * 如果指定,则登录时会检查所登陆的 bot 的用户名是否与此相等 + * @param master morny 实例所信任的主人的 id。用于初始化 {@link #trusted} + * @param trustedChat morny 实例所信任的群组的 id。用于初始化 {@link #trusted} * @param latestEventTimestamp 事件处理器会处理事件的最早时间戳 —— * 只有限定的 message 事件会受此影响。 * 单位为毫秒 */ - public static void main (@Nonnull String botKey, @Nullable String botUsername, long latestEventTimestamp) { - - MornyCoeur.latestEventTimestamp = latestEventTimestamp; - - logger.info("System Starting"); + private MornyCoeur ( + @Nonnull String botKey, @Nullable String botUsername, + long master, long trustedChat, long latestEventTimestamp + ) { + this.latestEventTimestamp = latestEventTimestamp; configureSafeExit(); logger.info("args key:\n " + botKey); @@ -65,23 +75,57 @@ public class MornyCoeur { logger.info("login as:\n " + botUsername); } - try { account = login(botKey); } - catch (Exception e) { logger.error("Cannot login to bot/api. :\n " + e.getMessage()); System.exit(-1); } + try { + final LogInResult loginResult = login(botKey); + this.account = loginResult.account; + this.username = loginResult.username; + this.trusted = new MornyTrusted(master, trustedChat); + logger.info(String.format(""" + trusted param set: + - master (id) + %d + - trusted chat (id) + %d""", + master, trustedChat + )); + } + catch (Exception e) { + RuntimeException ex = new RuntimeException("Cannot login to bot/api. :\n " + e.getMessage()); + logger.error(ex.getMessage()); + throw ex; + } logger.info("Bot login succeed."); - TrackerDataManager.init(); - EventListeners.registerAllListeners(); - account.setUpdatesListener(OnUpdate::onNormalUpdate); - - logger.info("System start complete"); - + } + + /** + * 向外界暴露的 morny 初始化入口. + *

+ * 如果 morny 已经初始化,则不会进行初始化,抛出错误消息并直接退出方法。 + * + * @see #MornyCoeur 程序初始化方法 + */ + public static void main ( + @Nonnull String botKey, @Nullable String botUsername, + long master, long trustedChat, long latestEventTimestamp + ) { + if (INSTANCE == null) { + logger.info("System Starting"); + INSTANCE = new MornyCoeur(botKey, botUsername, master, trustedChat, latestEventTimestamp); + TrackerDataManager.init(); + EventListeners.registerAllListeners(); + INSTANCE.account.setUpdatesListener(OnUpdate::onNormalUpdate); + logger.info("System start complete"); + return; + } + logger.error("System already started coeur!!!"); } /** * 用于退出时进行缓存的任务处理等进行安全退出 */ - private static void exitCleanup () { + private void exitCleanup () { TrackerDataManager.DAEMON.interrupt(); TrackerDataManager.trackingLock.lock(); } @@ -89,8 +133,8 @@ public class MornyCoeur { /** * 为程序在虚拟机上添加退出钩子 */ - private static void configureSafeExit () { - Runtime.getRuntime().addShutdownHook(new Thread(MornyCoeur::exitCleanup)); + private void configureSafeExit () { + Runtime.getRuntime().addShutdownHook(new Thread(this::exitCleanup)); } /** @@ -104,18 +148,17 @@ public class MornyCoeur { * @return 成功登录后的 {@link TelegramBot} 对象 */ @Nonnull - public static TelegramBot login (@Nonnull String key) { + private LogInResult login (@Nonnull String key) { final TelegramBot account = new TelegramBot(key); logger.info("Trying to login..."); for (int i = 1; i < 4; i++) { if (i != 1) logger.info("retrying..."); try { final String username = account.execute(new GetMe()).user().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; + if (this.username != null && !this.username.equals(username)) + throw new RuntimeException("Required the bot @" + this.username + " but @" + username + " logged in!"); logger.info("Succeed login to @" + username); - return account; + return new LogInResult(account, username); } catch (Exception e) { e.printStackTrace(System.out); logger.error("login failed."); @@ -129,8 +172,9 @@ public class MornyCoeur { * * @return {@link #account MornyCoeur.account} */ + @Nonnull public static TelegramBot getAccount () { - return account; + return INSTANCE.account; } /** @@ -138,8 +182,29 @@ public class MornyCoeur { * * @return {@link #username MornyCoeur.username} */ + @Nonnull public static String getUsername () { - return username; + return INSTANCE.username; + } + + /** + * + * 获取忽略时间点 + * + * @return {@link #latestEventTimestamp MornyCoeur.latestEventTimestamp} + */ + public static long getLatestEventTimestamp () { + return INSTANCE.latestEventTimestamp; + } + + /** + * 获取 Morny 的{@link MornyTrusted 信任验证机} + * + * @return {@link #trusted MornyCoeur.trusted} + */ + @Nonnull + public static MornyTrusted trustedInstance () { + return INSTANCE.trusted; } } diff --git a/src/main/java/cc/sukazyo/cono/morny/MornyTrusted.java b/src/main/java/cc/sukazyo/cono/morny/MornyTrusted.java index c2a07de..f892b9d 100644 --- a/src/main/java/cc/sukazyo/cono/morny/MornyTrusted.java +++ b/src/main/java/cc/sukazyo/cono/morny/MornyTrusted.java @@ -12,13 +12,18 @@ public class MornyTrusted { * 群聊id,其指向的群聊指示了哪个群的成员是受信任的 * @see #isTrusted(long) 受信检查 */ - public static final long TRUSTED_CHAT_ID = -1001541451710L; + public final Long TRUSTED_CHAT_ID; /** * morny 的主人
* 这项值的对象总是会被认为是可信任的 */ - public static final long MASTER = 793274677L; + public final long MASTER; + + public MornyTrusted (long master, long trustedChatId) { + this.TRUSTED_CHAT_ID = trustedChatId; + this.MASTER = master; + } /** * 用于检查一个 telegram-user 是否受信任
@@ -30,7 +35,7 @@ public class MornyTrusted { * @param userId 需要检查的用户的id * @return 所传递的用户id对应的用户是否受信任 */ - public static boolean isTrusted (long userId) { + public boolean isTrusted (long userId) { if (userId == MASTER) return true; final ChatMember chatMember = MornyCoeur.getAccount().execute(new GetChatMember(TRUSTED_CHAT_ID, userId)).chatMember(); return ( diff --git a/src/main/java/cc/sukazyo/cono/morny/ServerMain.java b/src/main/java/cc/sukazyo/cono/morny/ServerMain.java index 78f1702..fcbe489 100644 --- a/src/main/java/cc/sukazyo/cono/morny/ServerMain.java +++ b/src/main/java/cc/sukazyo/cono/morny/ServerMain.java @@ -59,7 +59,7 @@ public class ServerMain { * 但实际上这并不影响现在的使用,选项赋值目前仍属于测试功能
* 但请勿混用,这将使两个赋值出现混淆并产生不可知的结果 * - * @see MornyCoeur#main(String, String, long) + * @see MornyCoeur#main(String, String, long, long, long) * @since 0.4.0.0 * @param args 参数组 */ @@ -68,6 +68,8 @@ public class ServerMain { String key = null; String username = null; boolean outdatedBlock = false; + long master = 793274677L; + long trustedChat = -1001541451710L; for (int i = 0; i < args.length; i++) { @@ -100,6 +102,16 @@ public class ServerMain { username = args[i]; continue; } + case "--master" -> { + i++; + master = Long.parseLong(args[i]); + continue; + } + case "--trusted-chat" -> { + i++; + trustedChat = Long.parseLong(args[i]); + continue; + } } } else { @@ -143,7 +155,7 @@ public class ServerMain { if (welcomeEchoMode) return; assert key != null; - MornyCoeur.main(key, username, outdatedBlock?System.currentTimeMillis():0); + MornyCoeur.main(key, username, master, trustedChat, outdatedBlock?System.currentTimeMillis():0); } diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/event/OnCallMe.java b/src/main/java/cc/sukazyo/cono/morny/bot/event/OnCallMe.java index c1c14e0..6d10041 100644 --- a/src/main/java/cc/sukazyo/cono/morny/bot/event/OnCallMe.java +++ b/src/main/java/cc/sukazyo/cono/morny/bot/event/OnCallMe.java @@ -23,7 +23,7 @@ public class OnCallMe extends EventListener { * 跟随 {@link MornyTrusted#MASTER} 的值 * @since 0.4.2.1 */ - private static final long ME = MornyTrusted.MASTER; + private static final long ME = MornyCoeur.trustedInstance().MASTER; /** * 监听私聊 bot 的消息进行呼叫关键字匹配。 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 5f5da75..3090192 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 @@ -3,7 +3,6 @@ package cc.sukazyo.cono.morny.bot.event; import cc.sukazyo.cono.morny.GradleProjectConfigures; import cc.sukazyo.cono.morny.MornyCoeur; import cc.sukazyo.cono.morny.MornySystem; -import cc.sukazyo.cono.morny.MornyTrusted; import cc.sukazyo.cono.morny.bot.api.EventListener; import cc.sukazyo.cono.morny.bot.api.InputCommand; import cc.sukazyo.cono.morny.bot.event.on_commands.EventHack; @@ -88,7 +87,7 @@ public class OnCommandExecute extends EventListener { } private void onCommandExitExec (@Nonnull Update event) { - if (MornyTrusted.isTrusted(event.message().from().id())) { + if (MornyCoeur.trustedInstance().isTrusted(event.message().from().id())) { MornyCoeur.getAccount().execute(new SendSticker( event.message().chat().id(), TelegramStickers.ID_EXIT 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 index 3f7068b..4b96284 100644 --- a/src/main/java/cc/sukazyo/cono/morny/bot/event/OnUpdateTimestampOffsetLock.java +++ b/src/main/java/cc/sukazyo/cono/morny/bot/event/OnUpdateTimestampOffsetLock.java @@ -17,30 +17,41 @@ import javax.annotation.Nonnull; *

  • {@link EventListener#onChannelPost(Update) 收到频道消息}
  • *
  • {@link EventListener#onEditedChannelPost(Update) 频道消息被更新}
  • * + * @see #isOutdated 时间判断 */ public class OnUpdateTimestampOffsetLock extends EventListener { + /** + * 检查传入时间是否在要求时间之前(即"过期"). + * @param timestamp 传入时间,秒级 + * @return 如果传入时间在要求时间之前,返回true,反之false + * @since 0.4.2.7 + */ + public boolean isOutdated(long timestamp) { + return timestamp < MornyCoeur.getLatestEventTimestamp()/1000; + } + @Override public boolean onMessage (@NotNull Update update) { - return update.message().date() < MornyCoeur.latestEventTimestamp/1000; + return isOutdated(update.message().date()); } /** @since 0.4.2.6 */ @Override public boolean onEditedMessage (@Nonnull Update update) { - return update.editedMessage().editDate() < MornyCoeur.latestEventTimestamp/1000; + return isOutdated(update.editedMessage().editDate()); } /** @since 0.4.2.6 */ @Override public boolean onChannelPost (@Nonnull Update update) { - return update.channelPost().date() < MornyCoeur.latestEventTimestamp/1000; + return isOutdated(update.channelPost().date()); } /** @since 0.4.2.6 */ @Override public boolean onEditedChannelPost (@Nonnull Update update) { - return update.editedChannelPost().editDate() < MornyCoeur.latestEventTimestamp/1000; + return isOutdated(update.editedChannelPost().editDate()); } } diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/event/on_commands/EventHack.java b/src/main/java/cc/sukazyo/cono/morny/bot/event/on_commands/EventHack.java index 94ad6cd..2146535 100644 --- a/src/main/java/cc/sukazyo/cono/morny/bot/event/on_commands/EventHack.java +++ b/src/main/java/cc/sukazyo/cono/morny/bot/event/on_commands/EventHack.java @@ -36,7 +36,7 @@ public class EventHack { switch (x_mode) { case "any": - if (MornyTrusted.isTrusted(event.message().from().id())) { + if (MornyCoeur.trustedInstance().isTrusted(event.message().from().id())) { OnEventHackHandle.registerHack( event.message().messageId(), event.message().from().id(),