From 1a31a22cd9fc7a84a00e060bbc27786d13413b05 Mon Sep 17 00:00:00 2001 From: Eyre_S Date: Thu, 7 Sep 2023 22:15:06 +0800 Subject: [PATCH] scala port stage2 (not tested) --- build.gradle | 9 +- gradle.properties | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- src/main/old/cc/sukazyo/cono/morny/Log.java | 3 +- .../old/cc/sukazyo/cono/morny/MornyCoeur.java | 19 +- .../cono/morny/bot/api/EventListener.java | 66 ---- .../morny/bot/api/EventListenerManager.java | 118 ------- .../cono/morny/bot/api/InlineQueryUnit.java | 36 --- .../sukazyo/cono/morny/bot/api/OnUpdate.java | 59 ---- .../morny/bot/command/ISimpleCommand.java | 19 -- .../morny/bot/command/ITelegramCommand.java | 12 - .../cono/morny/bot/command/MornyCommands.java | 297 ------------------ .../cono/morny/bot/event/EventListeners.java | 39 --- .../morny/bot/event/OnActivityRecord.java | 4 +- .../cono/morny/bot/event/OnCallMsgSend.java | 222 ------------- .../morny/bot/event/OnEventHackHandle.java | 145 --------- .../bot/event/OnKuohuanhuanNeedSleep.java | 2 +- .../bot/event/OnMedicationNotifyApply.java | 29 -- .../morny/bot/event/OnQuestionMarkReply.java | 38 --- .../morny/bot/event/OnRandomlyTriggered.java | 3 +- .../morny/bot/event/OnTelegramCommand.java | 30 -- .../morny/bot/event/OnUniMeowTrigger.java | 36 --- .../event/OnUpdateTimestampOffsetLock.java | 56 ---- .../cono/morny/daemon/MornyReport.java | 2 +- .../cc/sukazyo/cono/morny/data/MornyJrrp.java | 46 --- .../sukazyo/cono/morny/data/NbnhhshQuery.java | 47 --- .../tgapi/formatting/TGToStringFromChat.java | 39 ++- .../cono/morny/bot/api/EventListener.scala | 22 ++ .../morny/bot/api/EventListenerManager.scala | 84 +++++ .../bot/api/TelegramUpdatesListener.scala | 17 + .../morny/bot/command/DirectMsgClear.scala | 6 +- .../cono/morny/bot/command/Encryptor.scala | 10 +- .../cono/morny/bot/command/EventHack.scala | 10 +- .../morny/bot/command/GetUsernameAndId.scala | 15 +- .../morny/bot/command/ICommandAlias.scala | 18 ++ .../cono/morny/bot/command/IP186Query.scala | 22 +- .../morny/bot/command/ISimpleCommand.scala | 13 + .../morny/bot/command/ITelegramCommand.scala | 8 + .../morny/bot/command/MornyCommands.scala | 111 +++++++ .../cono/morny/bot/command/MornyHellos.scala | 43 +++ ...foOnHello.scala => MornyInfoOnStart.scala} | 8 +- .../morny/bot/command/MornyInformation.scala | 33 +- .../bot/command/MornyInformationOlds.scala | 17 + .../morny/bot/command/MornyManagers.scala | 86 +++++ .../cono/morny/bot/command/MornyOldJrrp.scala | 36 +++ .../cono/morny/bot/command/Nbnhhsh.scala | 26 +- .../cono/morny/bot/command/Testing.scala | 12 +- .../sukazyo/cono/morny/bot/command/喵呜.scala | 44 +-- .../cono/morny/bot/command/私わね.scala | 6 +- .../morny/bot/event/MornyEventListeners.scala | 27 ++ .../cono/morny/bot/event/OnCallMe.scala | 2 +- .../cono/morny/bot/event/OnCallMsgSend.scala | 153 +++++++++ .../morny/bot/event/OnEventHackHandle.scala | 80 +++++ .../cono/morny/bot/event/OnInlineQuery.scala | 7 +- .../bot/event/OnMedicationNotifyApply.scala | 21 ++ .../morny/bot/event/OnQuestionMarkReply.scala | 30 ++ .../morny/bot/event/OnTelegramCommand.scala | 34 ++ .../morny/bot/event/OnUniMeowTrigger.scala | 23 ++ .../event/OnUpdateTimestampOffsetLock.scala | 17 + .../cono/morny/bot/event/OnUserRandom.scala | 2 +- .../morny/bot/event/OnUserSlashAction.scala | 7 +- .../cono/morny/bot/query/ITelegramQuery.scala | 1 - .../morny/bot/query/InlineQueryUnit.scala | 27 ++ .../cono/morny/bot/query/MornyQueries.scala | 1 - .../cono/morny/bot/query/MyInformation.scala | 1 - .../cono/morny/bot/query/RawText.scala | 1 - .../morny/bot/query/ShareToolBilibili.scala | 1 - .../morny/bot/query/ShareToolTwitter.scala | 1 - .../sukazyo/cono/morny/data/MornyJrrp.scala | 17 + .../cono/morny/data/NbnhhshQuery.scala | 37 +++ .../morny/data/ip186/IP186QueryHandler.scala | 9 +- 71 files changed, 1093 insertions(+), 1433 deletions(-) delete mode 100644 src/main/old/cc/sukazyo/cono/morny/bot/api/EventListener.java delete mode 100644 src/main/old/cc/sukazyo/cono/morny/bot/api/EventListenerManager.java delete mode 100644 src/main/old/cc/sukazyo/cono/morny/bot/api/InlineQueryUnit.java delete mode 100644 src/main/old/cc/sukazyo/cono/morny/bot/api/OnUpdate.java delete mode 100644 src/main/old/cc/sukazyo/cono/morny/bot/command/ISimpleCommand.java delete mode 100644 src/main/old/cc/sukazyo/cono/morny/bot/command/ITelegramCommand.java delete mode 100644 src/main/old/cc/sukazyo/cono/morny/bot/command/MornyCommands.java delete mode 100644 src/main/old/cc/sukazyo/cono/morny/bot/event/EventListeners.java delete mode 100644 src/main/old/cc/sukazyo/cono/morny/bot/event/OnCallMsgSend.java delete mode 100644 src/main/old/cc/sukazyo/cono/morny/bot/event/OnEventHackHandle.java delete mode 100644 src/main/old/cc/sukazyo/cono/morny/bot/event/OnMedicationNotifyApply.java delete mode 100644 src/main/old/cc/sukazyo/cono/morny/bot/event/OnQuestionMarkReply.java delete mode 100644 src/main/old/cc/sukazyo/cono/morny/bot/event/OnTelegramCommand.java delete mode 100644 src/main/old/cc/sukazyo/cono/morny/bot/event/OnUniMeowTrigger.java delete mode 100644 src/main/old/cc/sukazyo/cono/morny/bot/event/OnUpdateTimestampOffsetLock.java delete mode 100644 src/main/old/cc/sukazyo/cono/morny/data/MornyJrrp.java delete mode 100644 src/main/old/cc/sukazyo/cono/morny/data/NbnhhshQuery.java create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/api/EventListener.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/api/EventListenerManager.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/api/TelegramUpdatesListener.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/command/ICommandAlias.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/command/ISimpleCommand.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/command/ITelegramCommand.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyCommands.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyHellos.scala rename src/main/scala/cc/sukazyo/cono/morny/bot/command/{MornyInfoOnHello.scala => MornyInfoOnStart.scala} (79%) create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyInformationOlds.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyManagers.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyOldJrrp.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/event/MornyEventListeners.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/event/OnCallMsgSend.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/event/OnEventHackHandle.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/event/OnMedicationNotifyApply.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/event/OnQuestionMarkReply.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/event/OnTelegramCommand.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/event/OnUniMeowTrigger.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/event/OnUpdateTimestampOffsetLock.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/query/InlineQueryUnit.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/data/MornyJrrp.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/data/NbnhhshQuery.scala diff --git a/build.gradle b/build.gradle index a15ac59..4d45291 100644 --- a/build.gradle +++ b/build.gradle @@ -99,8 +99,8 @@ scala { compileJava { - sourceCompatibility '17' - targetCompatibility '17' + sourceCompatibility proj_java.getMajorVersion() + targetCompatibility proj_java.getMajorVersion() options.encoding = proj_file_encoding.name() @@ -108,9 +108,14 @@ scala { compileScala { + sourceCompatibility proj_java.getMajorVersion() + targetCompatibility proj_java.getMajorVersion() + options.encoding = proj_file_encoding.name() scalaCompileOptions.encoding = proj_file_encoding.name() +// scalaCompileOptions.additionalParameters.add("-Yexplicit-nulls") + } } diff --git a/gradle.properties b/gradle.properties index 908c69b..4f1df34 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,7 +8,7 @@ MORNY_COMMIT_PATH = https://github.com/Eyre-S/Coeur-Morny-Cono/commit/%s VERSION = 1.0.0-RC4 USE_DELTA = true -VERSION_DELTA = scalaport1 +VERSION_DELTA = scalaport2 CODENAME = beiping diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 84a0b92..db9a6b8 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/main/old/cc/sukazyo/cono/morny/Log.java b/src/main/old/cc/sukazyo/cono/morny/Log.java index 4c3dadd..57ab124 100644 --- a/src/main/old/cc/sukazyo/cono/morny/Log.java +++ b/src/main/old/cc/sukazyo/cono/morny/Log.java @@ -5,6 +5,7 @@ import cc.sukazyo.messiva.log.LogLevel; import cc.sukazyo.messiva.logger.Logger; import cc.sukazyo.messiva.appender.ConsoleAppender; +import javax.annotation.Nonnull; import java.io.PrintWriter; import java.io.StringWriter; @@ -48,7 +49,7 @@ public class Log { * @return {@link String} 格式的异常的堆栈报告信息. * @see 1.0.0-alpha5 */ - public static String exceptionLog (Exception e) { + public static String exceptionLog (@Nonnull Throwable e) { final StringWriter stackTrace = new StringWriter(); e.printStackTrace(new PrintWriter(stackTrace)); return stackTrace.toString(); diff --git a/src/main/old/cc/sukazyo/cono/morny/MornyCoeur.java b/src/main/old/cc/sukazyo/cono/morny/MornyCoeur.java index 517332d..e6d201d 100644 --- a/src/main/old/cc/sukazyo/cono/morny/MornyCoeur.java +++ b/src/main/old/cc/sukazyo/cono/morny/MornyCoeur.java @@ -1,8 +1,8 @@ package cc.sukazyo.cono.morny; -import cc.sukazyo.cono.morny.bot.api.OnUpdate; +import cc.sukazyo.cono.morny.bot.api.TelegramUpdatesListener$; import cc.sukazyo.cono.morny.bot.command.MornyCommands; -import cc.sukazyo.cono.morny.bot.event.EventListeners; +import cc.sukazyo.cono.morny.bot.event.MornyEventListeners; import cc.sukazyo.cono.morny.bot.query.MornyQueries; import cc.sukazyo.cono.morny.daemon.MornyDaemons; import cc.sukazyo.cono.morny.daemon.TrackerDataManager; @@ -31,8 +31,6 @@ public class MornyCoeur { /** 当前 Morny 的{@link MornyTrusted 信任验证机}实例 */ private final MornyTrusted trusted; - /** 当前 Morny 的 telegram 命令管理器 */ - private final MornyCommands commandManager = new MornyCommands(); private final MornyQueries queryManager = new MornyQueries(); /** morny 的 bot 账户 */ @@ -127,12 +125,12 @@ public class MornyCoeur { MornyDaemons.start(); logger.info("start telegram events listening"); - EventListeners.registerAllListeners(); - INSTANCE.account.setUpdatesListener(OnUpdate::onNormalUpdate); + MornyEventListeners.registerAllEvents(); + INSTANCE.account.setUpdatesListener(TelegramUpdatesListener$.MODULE$); if (config.commandLoginRefresh) { logger.info("resetting telegram command list"); - commandManager().automaticUpdateList(); + MornyCommands.automaticTGListUpdate(); } logger.info("Coeur start complete"); @@ -156,7 +154,7 @@ public class MornyCoeur { private void exitCleanup () { MornyDaemons.stop(); if (config.commandLogoutClear) { - commandManager.automaticRemoveList(); + MornyCommands.automaticTGListRemove(); } } @@ -288,11 +286,6 @@ public class MornyCoeur { return INSTANCE.trusted; } - @Nonnull - public static MornyCommands commandManager () { - return INSTANCE.commandManager; - } - @Nonnull public static MornyQueries queryManager () { return INSTANCE.queryManager; diff --git a/src/main/old/cc/sukazyo/cono/morny/bot/api/EventListener.java b/src/main/old/cc/sukazyo/cono/morny/bot/api/EventListener.java deleted file mode 100644 index a7c8c5e..0000000 --- a/src/main/old/cc/sukazyo/cono/morny/bot/api/EventListener.java +++ /dev/null @@ -1,66 +0,0 @@ -package cc.sukazyo.cono.morny.bot.api; - -import com.pengrad.telegrambot.model.Update; - -import javax.annotation.Nonnull; - -@SuppressWarnings("unused") -public abstract class EventListener { - - public boolean onMessage (@Nonnull Update update) { - return false; - } - - public boolean onEditedMessage (@Nonnull Update update) { - return false; - } - - public boolean onChannelPost (@Nonnull Update update) { - return false; - } - - public boolean onEditedChannelPost (@Nonnull Update update) { - return false; - } - - public boolean onInlineQuery (@Nonnull Update update) { - return false; - } - - public boolean onChosenInlineResult (@Nonnull Update update) { - return false; - } - - public boolean onCallbackQuery (@Nonnull Update update) { - return false; - } - - public boolean onShippingQuery (@Nonnull Update update) { - return false; - } - - public boolean onPreCheckoutQuery (@Nonnull Update update) { - return false; - } - - public boolean onPoll (@Nonnull Update update) { - return false; - } - - public boolean onPollAnswer (@Nonnull Update update) { - return false; - } - - public boolean onMyChatMemberUpdated (@Nonnull Update update) { - return false; - } - - public boolean onChatMemberUpdated (@Nonnull Update update) { - return false; - } - - public boolean onChatJoinRequest (@Nonnull Update update) { - return false; - } - -} diff --git a/src/main/old/cc/sukazyo/cono/morny/bot/api/EventListenerManager.java b/src/main/old/cc/sukazyo/cono/morny/bot/api/EventListenerManager.java deleted file mode 100644 index 671dfd3..0000000 --- a/src/main/old/cc/sukazyo/cono/morny/bot/api/EventListenerManager.java +++ /dev/null @@ -1,118 +0,0 @@ -package cc.sukazyo.cono.morny.bot.api; - -import cc.sukazyo.cono.morny.Log; -import cc.sukazyo.cono.morny.daemon.MornyReport; -import cc.sukazyo.cono.morny.util.tgapi.event.EventRuntimeException; -import com.google.gson.GsonBuilder; -import com.pengrad.telegrambot.model.Update; - -import javax.annotation.Nonnull; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.function.Function; - -import static cc.sukazyo.cono.morny.Log.logger; - -public class EventListenerManager { - - private static final List listeners = new ArrayList<>(); - - private static class EventPublisher extends Thread { - - private final Function exec; - - public EventPublisher(@Nonnull Update update, @Nonnull Function exec) { - this.setName("EVT"+update.updateId()); - this.exec = exec; - } - - @Override - public void run () { - for (EventListener x : listeners) { - try { - - if (exec.apply(x)) return; - - } catch (Exception e) { - - final StringBuilder errorMessage = new StringBuilder(); - errorMessage.append("Event throws unexpected exception:\n"); - errorMessage.append(Log.exceptionLog(e).indent(4)); - if (e instanceof EventRuntimeException.ActionFailed) { - errorMessage.append("\ntg-api action: response track: "); - errorMessage.append(new GsonBuilder().setPrettyPrinting().create().toJson( - ((EventRuntimeException.ActionFailed)e).getResponse() - ).indent(4)).append('\n'); - } - logger.error(errorMessage.toString()); - - MornyReport.exception(e, "on event running"); - - } - } - } - - } - - public static void addListener (@Nonnull EventListener... listeners) { - EventListenerManager.listeners.addAll(Arrays.asList(listeners)); - } - - public static void publishMessageEvent (@Nonnull Update update) { - new EventPublisher(update, x -> x.onMessage(update)).start(); - } - - public static void publishEditedMessageEvent (@Nonnull Update update) { - new EventPublisher(update, x -> x.onEditedMessage(update)).start(); - } - - public static void publishChannelPostEvent (@Nonnull Update update) { - new EventPublisher(update, x -> x.onChannelPost(update)).start(); - } - - public static void publishEditedChannelPostEvent (@Nonnull Update update) { - new EventPublisher(update, x -> x.onEditedChannelPost(update)).start(); - } - - public static void publishInlineQueryEvent (@Nonnull Update update) { - new EventPublisher(update, x -> x.onInlineQuery(update)).start(); - } - - public static void publishChosenInlineResultEvent (@Nonnull Update update) { - new EventPublisher(update, x -> x.onChosenInlineResult(update)).start(); - } - - public static void publishCallbackQueryEvent (@Nonnull Update update) { - new EventPublisher(update, x -> x.onCallbackQuery(update)).start(); - } - - public static void publishShippingQueryEvent (@Nonnull Update update) { - new EventPublisher(update, x -> x.onShippingQuery(update)).start(); - } - - public static void publishPreCheckoutQueryEvent (@Nonnull Update update) { - new EventPublisher(update, x -> x.onPreCheckoutQuery(update)).start(); - } - - public static void publishPollEvent (@Nonnull Update update) { - new EventPublisher(update, x -> x.onPoll(update)).start(); - } - - public static void publishPollAnswerEvent (@Nonnull Update update) { - new EventPublisher(update, x -> x.onPollAnswer(update)).start(); - } - - public static void publishMyChatMemberUpdatedEvent (@Nonnull Update update) { - new EventPublisher(update, x -> x.onMyChatMemberUpdated(update)).start(); - } - - public static void publishChatMemberUpdatedEvent (@Nonnull Update update) { - new EventPublisher(update, x -> x.onChatMemberUpdated(update)).start(); - } - - public static void publishChatJoinRequestEvent (@Nonnull Update update) { - new EventPublisher(update, x -> x.onChatJoinRequest(update)).start(); - } - -} diff --git a/src/main/old/cc/sukazyo/cono/morny/bot/api/InlineQueryUnit.java b/src/main/old/cc/sukazyo/cono/morny/bot/api/InlineQueryUnit.java deleted file mode 100644 index 43f0376..0000000 --- a/src/main/old/cc/sukazyo/cono/morny/bot/api/InlineQueryUnit.java +++ /dev/null @@ -1,36 +0,0 @@ -package cc.sukazyo.cono.morny.bot.api; - -import com.pengrad.telegrambot.model.request.InlineQueryResult; - -public class InlineQueryUnit> { - - public static final int DEFAULT_INLINE_CACHE_TIME = 300; - public static final boolean DEFAULT_INLINE_PERSONAL_RESP = false; - - private int cacheTime = DEFAULT_INLINE_CACHE_TIME; - private boolean isPersonal = DEFAULT_INLINE_PERSONAL_RESP; - public final T result; - - public InlineQueryUnit (T result) { - this.result = result; - } - - public int cacheTime () { - return cacheTime; - } - - public InlineQueryUnit cacheTime (int cacheTime) { - this.cacheTime = cacheTime; - return this; - } - - public boolean isPersonal () { - return isPersonal; - } - - public InlineQueryUnit isPersonal (boolean isPersonal) { - this.isPersonal = isPersonal; - return this; - } - -} diff --git a/src/main/old/cc/sukazyo/cono/morny/bot/api/OnUpdate.java b/src/main/old/cc/sukazyo/cono/morny/bot/api/OnUpdate.java deleted file mode 100644 index e03653b..0000000 --- a/src/main/old/cc/sukazyo/cono/morny/bot/api/OnUpdate.java +++ /dev/null @@ -1,59 +0,0 @@ -package cc.sukazyo.cono.morny.bot.api; - -import com.pengrad.telegrambot.UpdatesListener; -import com.pengrad.telegrambot.model.Update; - -import javax.annotation.Nonnull; -import java.util.List; - -public class OnUpdate { - - public static int onNormalUpdate (@Nonnull List updates) { - for (Update update : updates) { - if (update.message() != null) { - EventListenerManager.publishMessageEvent(update); - } - if (update.editedMessage() != null) { - EventListenerManager.publishEditedMessageEvent(update); - } - if (update.channelPost() != null) { - EventListenerManager.publishChannelPostEvent(update); - } - if (update.editedChannelPost() != null) { - EventListenerManager.publishEditedChannelPostEvent(update); - } - if (update.inlineQuery() != null) { - EventListenerManager.publishInlineQueryEvent(update); - } - if (update.chosenInlineResult() != null) { - EventListenerManager.publishChosenInlineResultEvent(update); - } - if (update.callbackQuery() != null) { - EventListenerManager.publishCallbackQueryEvent(update); - } - if (update.shippingQuery() != null) { - EventListenerManager.publishShippingQueryEvent(update); - } - if (update.preCheckoutQuery() != null) { - EventListenerManager.publishPreCheckoutQueryEvent(update); - } - if (update.poll() != null) { - EventListenerManager.publishPollEvent(update); - } - if (update.pollAnswer() != null) { - EventListenerManager.publishPollAnswerEvent(update); - } - if (update.myChatMember() != null) { - EventListenerManager.publishMyChatMemberUpdatedEvent(update); - } - if (update.chatMember() != null) { - EventListenerManager.publishChatMemberUpdatedEvent(update); - } - if (update.chatJoinRequest() != null) { - EventListenerManager.publishChatJoinRequestEvent(update); - } - } - return UpdatesListener.CONFIRMED_UPDATES_ALL; - } - -} diff --git a/src/main/old/cc/sukazyo/cono/morny/bot/command/ISimpleCommand.java b/src/main/old/cc/sukazyo/cono/morny/bot/command/ISimpleCommand.java deleted file mode 100644 index 453a97e..0000000 --- a/src/main/old/cc/sukazyo/cono/morny/bot/command/ISimpleCommand.java +++ /dev/null @@ -1,19 +0,0 @@ -package cc.sukazyo.cono.morny.bot.command; - -import cc.sukazyo.cono.morny.util.tgapi.InputCommand; -import com.pengrad.telegrambot.model.Update; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -public interface ISimpleCommand { - - @Nonnull - String getName(); - - @Nullable - String[] getAliases(); - - void execute (@Nonnull InputCommand command, @Nonnull Update event); - -} diff --git a/src/main/old/cc/sukazyo/cono/morny/bot/command/ITelegramCommand.java b/src/main/old/cc/sukazyo/cono/morny/bot/command/ITelegramCommand.java deleted file mode 100644 index b090a95..0000000 --- a/src/main/old/cc/sukazyo/cono/morny/bot/command/ITelegramCommand.java +++ /dev/null @@ -1,12 +0,0 @@ -package cc.sukazyo.cono.morny.bot.command; - -import javax.annotation.Nonnull; - -public interface ITelegramCommand extends ISimpleCommand { - - @Nonnull - String getParamRule(); - @Nonnull - String getDescription(); - -} diff --git a/src/main/old/cc/sukazyo/cono/morny/bot/command/MornyCommands.java b/src/main/old/cc/sukazyo/cono/morny/bot/command/MornyCommands.java deleted file mode 100644 index d3cf37f..0000000 --- a/src/main/old/cc/sukazyo/cono/morny/bot/command/MornyCommands.java +++ /dev/null @@ -1,297 +0,0 @@ -package cc.sukazyo.cono.morny.bot.command; - -import cc.sukazyo.cono.morny.MornyCoeur; -import cc.sukazyo.cono.morny.bot.event.OnUniMeowTrigger; -import cc.sukazyo.cono.morny.daemon.MornyReport; -import cc.sukazyo.cono.morny.data.MornyJrrp; -import cc.sukazyo.cono.morny.data.TelegramStickers; -import cc.sukazyo.cono.morny.util.tgapi.InputCommand; -import cc.sukazyo.cono.morny.util.tgapi.formatting.TGToString; -import com.pengrad.telegrambot.model.BotCommand; -import com.pengrad.telegrambot.model.DeleteMyCommands; -import com.pengrad.telegrambot.model.Update; -import com.pengrad.telegrambot.model.request.ParseMode; -import com.pengrad.telegrambot.request.SendMessage; -import com.pengrad.telegrambot.request.SendSticker; -import com.pengrad.telegrambot.request.SetMyCommands; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import java.util.*; - -import static cc.sukazyo.cono.morny.Log.logger; -import static cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml; - -public class MornyCommands { - - private final Map commands = new LinkedHashMap<>(); - - private void pushCommandTo (@Nonnull String name, @Nonnull ISimpleCommand instance) { - if (commands.containsKey(name)) { - logger.warn(String.format(""" - Telegram command instance named "%s" already exists and will be override by another command instance - - current: %s - - new : %s""", - name, - commands.get(name).getClass().getName(), - instance.getClass().getName() - )); - } - commands.put(name, instance); - } - - public void register (@Nonnull ISimpleCommand... list) { - for (ISimpleCommand instance : list) { - final String[] aliases = instance.getAliases(); - pushCommandTo(instance.getName(), instance); - if (aliases!=null) for (String alias : aliases) pushCommandTo(alias, instance); - } - } - - @SuppressWarnings("NonAsciiCharacters") - public MornyCommands () { - - register( - new ON(), - new Hello(), /* new {@link HelloOnStart}, */ - MornyInformation$.MODULE$, - GetUsernameAndId$.MODULE$, - EventHack$.MODULE$, - Nbnhhsh$.MODULE$, - IP186Query.IP$.MODULE$, - IP186Query.Whois$.MODULE$, - Encryptor$.MODULE$, - new SaveData(), - MornyInfoOnHello$.MODULE$, - new Version(), - new MornyRuntime(), - new Jrrp(), - new Exit(), new ExitAlias() - ); - - // 特殊的命令 - register( - Testing$.MODULE$, - DirectMsgClear$.MODULE$ - ); - - // 统一注册这些奇怪的东西&.& - register( - 私わね$.MODULE$, - 喵呜.Progynova$.MODULE$ - ); - // special: 注册出于兼容使用的特别 event 的数据 - OnUniMeowTrigger.register( - 喵呜.抱抱$.MODULE$, - 喵呜.揉揉$.MODULE$, - 喵呜.蹭蹭$.MODULE$, - 喵呜.贴贴$.MODULE$ - ); - - } - - public boolean execute (@Nonnull InputCommand command, @Nonnull Update event) { - if (commands.containsKey(command.getCommand())) { - commands.get(command.getCommand()).execute(command, event); - return true; - } - return nonCommandExecutable(event, command); - } - - public void automaticUpdateList () { - BotCommand[] commandList = getCommandListTelegram(); - automaticRemoveList(); - MornyCoeur.extra().exec(new SetMyCommands( - commandList - )); - logger.info("automatic updated telegram command list :\n" + commandListToString(commandList)); - } - - public void automaticRemoveList () { - MornyCoeur.extra().exec(new DeleteMyCommands()); - logger.info("cleaned up command list."); - } - - 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 telegramFormatListing = new ArrayList<>(); - commands.forEach((regKey, command) -> { - if (command instanceof ITelegramCommand && regKey.equals(command.getName())) { - telegramFormatListing.add(formatTelegramCommandListLine( - command.getName(), - ((ITelegramCommand)command).getParamRule(), - ((ITelegramCommand)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, paramRule.isEmpty() ? (intro) : (paramRule+" - "+intro)); - } - - private boolean nonCommandExecutable (Update event, InputCommand command) { - if (command.getTarget() == null) return false; // 无法解析的命令,转交事件链后代处理 - else { // 无法解析的显式命令格式,报错找不到命令 - MornyCoeur.extra().exec(new SendSticker( - event.message().chat().id(), - TelegramStickers.ID_404 - ).replyToMessageId(event.message().messageId()) - ); - return true; - } - } - - /// /// /// /// /// /// /// /// /// - /// - /// Old Simple Command Block - /// - - private static class ON implements ITelegramCommand { - @Nonnull @Override public String getName () { return "o"; } - @Nullable - @Override public String[] getAliases () { return null; } - @Nonnull @Override public String getParamRule () { return ""; } - @Nonnull @Override public String getDescription () { return "检查是否在线"; } - @Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { onCommandOnExec(event); } - } - private static void onCommandOnExec (@Nonnull Update event) { - MornyCoeur.extra().exec(new SendSticker( - event.message().chat().id(), - TelegramStickers.ID_ONLINE_STATUS_RETURN - ).replyToMessageId(event.message().messageId()) - ); - } - - private static class Hello implements ITelegramCommand { - @Nonnull @Override public String getName () { return "hello"; } - @Nullable @Override public String[] getAliases () { return new String[]{"hi"}; } - @Nonnull @Override public String getParamRule () { return ""; } - @Nonnull @Override public String getDescription () { return "打招呼"; } - @Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { onCommandHelloExec(event); } - } - /** - * {@link Hello} on special command /start - * Deprecated due to new {@link MornyInfoOnHello} - */ - @Deprecated @SuppressWarnings("unused") - private static class HelloOnStart implements ISimpleCommand { @Nonnull @Override public String getName () { return "start"; }@Nullable @Override public String[] getAliases () { return new String[0]; }@Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { onCommandHelloExec(event); }} - private static void onCommandHelloExec (@Nonnull Update event) { - MornyCoeur.extra().exec(new SendSticker( - event.message().chat().id(), - TelegramStickers.ID_HELLO - ).replyToMessageId(event.message().messageId()) - ); - } - - private static class Exit implements ITelegramCommand { - @Nonnull @Override public String getName () { return "exit"; } - @Nullable @Override public String[] getAliases () { return new String[0]; } - @Nonnull @Override public String getParamRule () { return ""; } - @Nonnull @Override public String getDescription () { return "关闭 Bot (仅可信成员)"; } - @Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { onCommandExitExec(event); } - } - private static class ExitAlias implements ISimpleCommand { - @Nonnull @Override public String getName () { return "quit"; } - @Nullable @Override public String[] getAliases () { return new String[]{"stop"}; } - @Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { onCommandExitExec(event); } - } - private static void onCommandExitExec (@Nonnull Update event) { - if (MornyCoeur.trustedInstance().isTrusted(event.message().from().id())) { - MornyCoeur.extra().exec(new SendSticker( - event.message().chat().id(), - TelegramStickers.ID_EXIT - ).replyToMessageId(event.message().messageId()) - ); - logger.info("Morny exited by user " + TGToString.as(event.message().from()).toStringLogTag()); - MornyCoeur.exit(0, event.message().from()); - } else { - MornyCoeur.extra().exec(new SendSticker( - event.message().chat().id(), - TelegramStickers.ID_403 - ).replyToMessageId(event.message().messageId()) - ); - logger.info("403 exited tag from user " + TGToString.as(event.message().from()).toStringLogTag()); - MornyReport.unauthenticatedAction("/exit", event.message().from()); - } - } - - private static class Version implements ISimpleCommand { - @Nonnull @Override public String getName () { return "version"; } - @Nullable @Override public String[] getAliases () { return null; } - @Nonnull @Deprecated public String getParamRule () { return ""; } - @Nonnull @Deprecated public String getDescription () { return "检查 Bot 版本信息"; } - @Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { MornyInformation.echoVersion(event); } - } - - private static class MornyRuntime implements ISimpleCommand { - @Nonnull @Override public String getName () { return "runtime"; } - @Nullable @Override public String[] getAliases () { return null; } - @Nonnull @Deprecated public String getParamRule () { return ""; } - @Nonnull @Deprecated public String getDescription () { return "获取 Bot 运行时信息(包括版本号)"; } - @Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { MornyInformation.echoRuntime(event); } - } - - private static class Jrrp implements ITelegramCommand { - @Nonnull @Override public String getName () { return "jrrp"; } - @Nullable @Override public String[] getAliases () { return null; } - @Nonnull @Override public String getParamRule () { return ""; } - @Nonnull @Override public String getDescription () { return "获取 (假的) jrrp"; } - @Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { onCommandJrrpExec(event); } - } - private static void onCommandJrrpExec (Update event) { - final double jrrp = MornyJrrp.getJrrpFromTelegramUser(event.message().from(), System.currentTimeMillis()); - final String endChar = jrrp>70 ? "!" : jrrp>30 ? ";" : "..."; - MornyCoeur.extra().exec(new SendMessage( - event.message().chat().id(), - String.format( - "%s 在(utc的)今天的运气指数是———— %.2f%% %s", - TGToString.as(event.message().from()).fullnameRefHtml(), - jrrp, escapeHtml(endChar) - ) - ).replyToMessageId(event.message().messageId()).parseMode(ParseMode.HTML)); - } - - private static class SaveData implements ITelegramCommand { - @Nonnull @Override public String getName () { return "save"; } - @Nullable @Override public String[] getAliases () { return null; } - @Nonnull @Override public String getParamRule () { return ""; } - @Nonnull @Override public String getDescription () { return "保存缓存数据到文件(仅可信成员)"; } - @Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { onSaveDataExec(event); } - } - /** - * @since 0.4.3.0 - */ - private static void onSaveDataExec (Update event) { - if (MornyCoeur.trustedInstance().isTrusted(event.message().from().id())) { - logger.info("called save from command by " + TGToString.as(event.message().from()).toStringLogTag()); - MornyCoeur.callSaveData(); - MornyCoeur.extra().exec(new SendSticker( - event.message().chat().id(), - TelegramStickers.ID_SAVED - ).replyToMessageId(event.message().messageId()) - ); - } else { - MornyCoeur.extra().exec(new SendSticker( - event.message().chat().id(), - TelegramStickers.ID_403 - ).replyToMessageId(event.message().messageId()) - ); - logger.info("403 call save tag from user " + TGToString.as(event.message().from()).toStringLogTag()); - MornyReport.unauthenticatedAction("/save", event.message().from()); - } - } - -} diff --git a/src/main/old/cc/sukazyo/cono/morny/bot/event/EventListeners.java b/src/main/old/cc/sukazyo/cono/morny/bot/event/EventListeners.java deleted file mode 100644 index f60095e..0000000 --- a/src/main/old/cc/sukazyo/cono/morny/bot/event/EventListeners.java +++ /dev/null @@ -1,39 +0,0 @@ -package cc.sukazyo.cono.morny.bot.event; - -import cc.sukazyo.cono.morny.bot.api.EventListenerManager; -import cc.sukazyo.cono.morny.bot.api.InlineQueryUnit; - -public class EventListeners { - - public static final OnTelegramCommand COMMANDS_LISTENER = new OnTelegramCommand(); -// public static final OnActivityRecord ACTIVITY_RECORDER = new OnActivityRecord(); - public static final OnUpdateTimestampOffsetLock UPDATE_TIMESTAMP_OFFSET_LOCK = new OnUpdateTimestampOffsetLock(); - public static final OnEventHackHandle EVENT_HACK_HANDLE = new OnEventHackHandle(); -// static final OnKuohuanhuanNeedSleep KUOHUANHUAN_NEED_SLEEP = new OnKuohuanhuanNeedSleep(); - public static final OnCallMsgSend CALL_MSG_SEND = new OnCallMsgSend(); - public static final OnMedicationNotifyApply MEDICATION_NOTIFY_APPLY = new OnMedicationNotifyApply(); - public static final OnRandomlyTriggered RANDOMLY_TRIGGERED = new OnRandomlyTriggered(); - public static final OnUniMeowTrigger UNI_MEOW_TRIGGER = new OnUniMeowTrigger(); - public static final OnQuestionMarkReply QUESTION_MARK_REPLY = new OnQuestionMarkReply(); - - public static void registerAllListeners () { - EventListenerManager.addListener( -// ACTIVITY_RECORDER, - UPDATE_TIMESTAMP_OFFSET_LOCK, - /* write functional event behind here */ -// KUOHUANHUAN_NEED_SLEEP, - COMMANDS_LISTENER, - UNI_MEOW_TRIGGER, - RANDOMLY_TRIGGERED, - OnUserRandom$.MODULE$, - QUESTION_MARK_REPLY, - OnUserSlashAction$.MODULE$, - OnInlineQuery$.MODULE$, - OnCallMe$.MODULE$, - CALL_MSG_SEND, - MEDICATION_NOTIFY_APPLY, - EVENT_HACK_HANDLE - ); - } - -} diff --git a/src/main/old/cc/sukazyo/cono/morny/bot/event/OnActivityRecord.java b/src/main/old/cc/sukazyo/cono/morny/bot/event/OnActivityRecord.java index 8ad0af4..e099fb7 100644 --- a/src/main/old/cc/sukazyo/cono/morny/bot/event/OnActivityRecord.java +++ b/src/main/old/cc/sukazyo/cono/morny/bot/event/OnActivityRecord.java @@ -8,7 +8,7 @@ import com.pengrad.telegrambot.model.Update; import javax.annotation.Nonnull; @Deprecated -public class OnActivityRecord extends EventListener { +public class OnActivityRecord implements EventListener { @Override public boolean onMessage (@Nonnull Update update) { @@ -22,7 +22,7 @@ public class OnActivityRecord extends EventListener { (long)update.message().date() * 1000 ); } - return super.onMessage(update); + return false; } } diff --git a/src/main/old/cc/sukazyo/cono/morny/bot/event/OnCallMsgSend.java b/src/main/old/cc/sukazyo/cono/morny/bot/event/OnCallMsgSend.java deleted file mode 100644 index b4eaaec..0000000 --- a/src/main/old/cc/sukazyo/cono/morny/bot/event/OnCallMsgSend.java +++ /dev/null @@ -1,222 +0,0 @@ -package cc.sukazyo.cono.morny.bot.event; - -import java.util.ArrayList; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import com.pengrad.telegrambot.model.Chat; -import com.pengrad.telegrambot.model.Message; -import com.pengrad.telegrambot.model.MessageEntity; -import com.pengrad.telegrambot.model.Update; -import com.pengrad.telegrambot.model.request.ParseMode; -import com.pengrad.telegrambot.request.GetChat; -import com.pengrad.telegrambot.request.SendMessage; -import com.pengrad.telegrambot.request.SendSticker; - -import cc.sukazyo.cono.morny.MornyCoeur; -import cc.sukazyo.cono.morny.bot.api.EventListener; -import cc.sukazyo.cono.morny.data.TelegramStickers; -import com.pengrad.telegrambot.response.GetChatResponse; -import com.pengrad.telegrambot.response.SendResponse; - -import static cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml; - - -public class OnCallMsgSend extends EventListener { - - private static final Pattern REGEX_MSG_SENDREQ_DATA_HEAD = Pattern.compile("^\\*msg(-?\\d+)(\\*\\S+)?(?:\\n([\\s\\S]+))?$"); - - private record MessageToSend ( - @Nullable String message, - @Nullable MessageEntity[] entities, - @Nullable ParseMode parseMode, - long targetId - ) { } - - @Override - public boolean onMessage(@Nonnull Update update) { - - // 执行体检查 - if (update.message().chat().type() != Chat.Type.Private) return false; - if (update.message().text() == null) return false; - if (!update.message().text().startsWith("*msg")) return false; - - // 权限检查 - if (!MornyCoeur.trustedInstance().isTrusted(update.message().from().id())) { - MornyCoeur.extra().exec(new SendSticker( - update.message().chat().id(), - TelegramStickers.ID_403 - ).replyToMessageId(update.message().messageId())); - return true; - } - - Message msgsendReqRaw; // 用户书写的发送请求原文 - MessageToSend msgsendReqBody; // 解析后的发送请求实例 - - // *msgsend 发送标识 - // 处理发送要求 - if (update.message().text().equals("*msgsend")) { - // 发送体处理 - if (update.message().replyToMessage() == null) return answer404(update); - msgsendReqBody = parseRequest(update.message().replyToMessage()); - if (msgsendReqBody == null || msgsendReqBody.message == null) return answer404(update); - // 执行发送任务 - SendResponse sendResponse = MornyCoeur.getAccount().execute(parseMessageToSend(msgsendReqBody)); - if (!sendResponse.isOk()) { // 发送失败 - MornyCoeur.extra().exec(new SendMessage( - update.message().chat().id(), - String.format(""" - %d FAILED - %s""", - sendResponse.errorCode(), - sendResponse.description() - ) - ).replyToMessageId(update.message().messageId()).parseMode(ParseMode.HTML)); - } else { // 发送成功信号 - MornyCoeur.extra().exec(new SendSticker( - update.message().chat().id(), - TelegramStickers.ID_SENT - ).replyToMessageId(update.message().messageId())); - } - return true; - // 发送完成/失败 - 事件结束 - } - - // *msg 检查标识 - if (update.message().text().equals("*msg")) { // 处理对曾经的原文的检查 - if (update.message().replyToMessage() == null) { - return answer404(update); - } - msgsendReqRaw = update.message().replyToMessage(); - } else if (update.message().text().startsWith("*msg")) { // 对接受到的原文进行检查 - msgsendReqRaw = update.message(); - } else { - return answer404(update); // 未定义的动作 - } - - // 对发送请求的用户原文进行解析 - msgsendReqBody = parseRequest(msgsendReqRaw); - if (msgsendReqBody == null) { - return answer404(update); - } - - // 输出发送目标信息 - GetChatResponse targetChatReq = MornyCoeur.getAccount().execute(new GetChat(msgsendReqBody.targetId())); - if (!targetChatReq.isOk()) { - MornyCoeur.extra().exec(new SendMessage( - update.message().chat().id(), - String.format(""" - %d FAILED - %s""", - targetChatReq.errorCode(), - targetChatReq.description() - ) - ).replyToMessageId(update.message().messageId()).parseMode(ParseMode.HTML)); - } else { - MornyCoeur.extra().exec(new SendMessage( - update.message().chat().id(), - targetChatReq.chat().type() == Chat.Type.Private ? ( - String.format(""" - %d@%s - 🔒 %s %s""", - msgsendReqBody.targetId(), - escapeHtml(targetChatReq.chat().type().name()), - escapeHtml(targetChatReq.chat().firstName()+(targetChatReq.chat().lastName()==null?"":" "+targetChatReq.chat().lastName())), - targetChatReq.chat().username()==null? - String.format("@@", targetChatReq.chat().id()): - (escapeHtml("@"+targetChatReq.chat().username())) - ) - ) : ( - String.format(""" - %d@%s::: - %s %s%s""", - msgsendReqBody.targetId(), - escapeHtml(targetChatReq.chat().type().name()), - switch (targetChatReq.chat().type()) { - case group -> "💭"; - case channel -> "📢"; - case supergroup -> "💬"; - default -> "⭕️"; - }, - escapeHtml(targetChatReq.chat().title()), - targetChatReq.chat().username() != null?String.format( - " @%s", escapeHtml(targetChatReq.chat().username()) - ):"" - ) - ) - ).replyToMessageId(update.message().messageId()).parseMode(ParseMode.HTML)); - } - // 发送文本测试 - if (msgsendReqBody.message == null) return true; - final SendResponse testSendResp = MornyCoeur.getAccount().execute( - parseMessageToSend(msgsendReqBody, update.message().chat().id()).replyToMessageId(update.message().messageId()) - ); - if (!testSendResp.isOk()) { - MornyCoeur.extra().exec(new SendMessage( - update.message().chat().id(), - String.format(""" - %d FAILED - %s""", - testSendResp.errorCode(), - testSendResp.description() - ) - ).replyToMessageId(update.message().messageId()).parseMode(ParseMode.HTML)); - } - - return true; - - } - - @Nullable - private static MessageToSend parseRequest (@Nonnull Message requestBody) { - - final Matcher matcher = REGEX_MSG_SENDREQ_DATA_HEAD.matcher(requestBody.text()); - if (matcher.matches()) { - long targetId = Long.parseLong(matcher.group(1)); - ParseMode parseMode = matcher.group(2) == null ? null : switch (matcher.group(2)) { - case "*markdown", "*md", "*m↓" -> ParseMode.MarkdownV2; - case "*md1" -> ParseMode.Markdown; - case "*html" -> ParseMode.HTML; - default -> null; - }; - final int offset = "*msg".length()+matcher.group(1).length()+(matcher.group(2)==null?0:matcher.group(2).length())+1; - final ArrayList entities = new ArrayList<>(); - if (requestBody.entities() != null) for (MessageEntity entity : requestBody.entities()) { - final MessageEntity parsed = new MessageEntity(entity.type(), entity.offset() - offset, entity.length()); - if (entity.url() != null) parsed.url(entity.url()); - if (entity.user() != null) parsed.user(entity.user()); - if (entity.language() != null) parsed.language(entity.language()); - entities.add(parsed); - } - return new MessageToSend(matcher.group(3), entities.toArray(MessageEntity[]::new), parseMode, targetId); - } - - return null; - - } - - @Nonnull - private static SendMessage parseMessageToSend (@Nonnull MessageToSend body) { - return parseMessageToSend(body, body.targetId); - } - - @Nonnull - private static SendMessage parseMessageToSend (@Nonnull MessageToSend body, long targetId) { - SendMessage sendingBody = new SendMessage(targetId, body.message); - if (body.entities != null) sendingBody.entities(body.entities); - if (body.parseMode != null) sendingBody.parseMode(body.parseMode); - return sendingBody; - } - - private static boolean answer404 (@Nonnull Update update) { - MornyCoeur.extra().exec(new SendSticker( - update.message().chat().id(), - TelegramStickers.ID_404 - ).replyToMessageId(update.message().messageId())); - return true; - } - -} diff --git a/src/main/old/cc/sukazyo/cono/morny/bot/event/OnEventHackHandle.java b/src/main/old/cc/sukazyo/cono/morny/bot/event/OnEventHackHandle.java deleted file mode 100644 index ffba9b5..0000000 --- a/src/main/old/cc/sukazyo/cono/morny/bot/event/OnEventHackHandle.java +++ /dev/null @@ -1,145 +0,0 @@ -package cc.sukazyo.cono.morny.bot.event; - -import cc.sukazyo.cono.morny.MornyCoeur; -import cc.sukazyo.cono.morny.bot.api.EventListener; -import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape; - -import com.google.gson.GsonBuilder; -import com.pengrad.telegrambot.model.Update; -import com.pengrad.telegrambot.model.request.ParseMode; -import com.pengrad.telegrambot.request.SendMessage; - -import javax.annotation.Nonnull; -import java.util.HashMap; -import java.util.Map; - -import static cc.sukazyo.cono.morny.Log.logger; - -/** - * 事件劫持与序列化工具. - * @since 0.4.2.0 - */ -public class OnEventHackHandle extends EventListener { - - /** 事件劫持请求列表 */ - private static final Map hackers = new HashMap<>(); - - /** - * 触发事件劫持的限定条件. - * @since 0.4.2.0 - */ - public enum HackType { - /** 只有相同用户发起的事件才会被触发 */ - USER, - /** 只有相同群组内发生的事件才会触发 */ - GROUP, - /** 任何事件都可以触发 */ - ANY - } - - public record Hacker(long fromChatId, long fromMessageId) { - @Override public String toString() { - return fromChatId + "/" + fromMessageId; - } - } - - /** - * @since 0.4.2.0 - */ - public static void registerHack(long fromMessageId, long fromUserId, long fromChatId, @Nonnull HackType type) { - String rec = null; - switch (type) { - case USER -> rec = String.format("((%d))", fromUserId); - case GROUP -> rec = String.format("{{%d}}", fromChatId); - case ANY -> rec = "[[]]"; - } - hackers.put(rec, new Hacker(fromChatId, fromMessageId)); - logger.debug("add hacker track " + rec); - } - - private boolean onEventHacked (Update update, long chatId, long fromUser) { - logger.debug(String.format("got event signed {{%d}}((%d))", chatId, fromUser)); - Hacker x; - x = hackers.remove(String.format("((%d))", fromUser)); - if (x == null) x = hackers.remove(String.format("{{%d}}", chatId)); - if (x == null) x = hackers.remove("[[]]"); - if (x == null) return false; - logger.debug("hacked event by " + x); - MornyCoeur.extra().exec(new SendMessage(x.fromChatId, String.format( - "%s", - MsgEscape.escapeHtml(new GsonBuilder().setPrettyPrinting().create().toJson(update)) - )).parseMode(ParseMode.HTML).replyToMessageId((int)x.fromMessageId)); - return true; - } - - @Override - public boolean onMessage (@Nonnull Update update) { - return onEventHacked(update, update.message().chat().id(), update.message().from().id()); - } - - @Override - public boolean onEditedMessage (@Nonnull Update update) { - return onEventHacked(update, update.editedMessage().chat().id(), update.editedMessage().from().id()); - } - - @Override - public boolean onChannelPost (@Nonnull Update update) { - return onEventHacked(update, update.channelPost().chat().id(), update.channelPost().chat().id()); - } - - @Override - public boolean onEditedChannelPost (@Nonnull Update update) { - return onEventHacked(update, update.editedChannelPost().chat().id(), update.editedChannelPost().chat().id()); - } - - @Override - public boolean onInlineQuery (@Nonnull Update update) { - return onEventHacked(update, 0, update.inlineQuery().from().id()); - } - - @Override - public boolean onChosenInlineResult (@Nonnull Update update) { - return onEventHacked(update, 0, update.chosenInlineResult().from().id()); - } - - @Override - public boolean onCallbackQuery (@Nonnull Update update) { - return onEventHacked(update, 0, update.callbackQuery().from().id()); - } - - @Override - public boolean onShippingQuery (@Nonnull Update update) { - return onEventHacked(update, 0, update.shippingQuery().from().id()); - } - - @Override - public boolean onPreCheckoutQuery (@Nonnull Update update) { - return onEventHacked(update, 0, update.preCheckoutQuery().from().id()); - } - - @Override - public boolean onPoll (@Nonnull Update update) { - return onEventHacked(update, 0, 0); - } - - @Override - public boolean onPollAnswer (@Nonnull Update update) { - return onEventHacked(update, 0, update.pollAnswer().user().id()); - } - - @Override - public boolean onMyChatMemberUpdated (@Nonnull Update update) { - return onEventHacked(update, update.myChatMember().chat().id(), update.myChatMember().from().id()); - } - - @Override - public boolean onChatMemberUpdated (@Nonnull Update update) { - return onEventHacked(update, update.chatMember().chat().id(), update.chatMember().from().id()); - } - - @Override - public boolean onChatJoinRequest (@Nonnull Update update) { - return onEventHacked(update, update.chatJoinRequest().chat().id(), update.chatJoinRequest().from().id()); - } - -} diff --git a/src/main/old/cc/sukazyo/cono/morny/bot/event/OnKuohuanhuanNeedSleep.java b/src/main/old/cc/sukazyo/cono/morny/bot/event/OnKuohuanhuanNeedSleep.java index 2a51a67..8af5bc5 100644 --- a/src/main/old/cc/sukazyo/cono/morny/bot/event/OnKuohuanhuanNeedSleep.java +++ b/src/main/old/cc/sukazyo/cono/morny/bot/event/OnKuohuanhuanNeedSleep.java @@ -11,7 +11,7 @@ import java.util.GregorianCalendar; import java.util.Locale; @Deprecated -public class OnKuohuanhuanNeedSleep extends EventListener { +public class OnKuohuanhuanNeedSleep implements EventListener { @Override public boolean onMessage (@Nonnull Update update) { diff --git a/src/main/old/cc/sukazyo/cono/morny/bot/event/OnMedicationNotifyApply.java b/src/main/old/cc/sukazyo/cono/morny/bot/event/OnMedicationNotifyApply.java deleted file mode 100644 index 59ec01c..0000000 --- a/src/main/old/cc/sukazyo/cono/morny/bot/event/OnMedicationNotifyApply.java +++ /dev/null @@ -1,29 +0,0 @@ -package cc.sukazyo.cono.morny.bot.event; - -import cc.sukazyo.cono.morny.MornyCoeur; -import cc.sukazyo.cono.morny.bot.api.EventListener; -import cc.sukazyo.cono.morny.daemon.MornyDaemons; -import com.pengrad.telegrambot.model.Message; -import com.pengrad.telegrambot.model.Update; - -import javax.annotation.Nonnull; - -public class OnMedicationNotifyApply extends EventListener { - - @Override - public boolean onEditedChannelPost (@Nonnull Update update) { - return editedMessageProcess(update.editedChannelPost()); - } - - @Override - public boolean onEditedMessage (@Nonnull Update update) { - return editedMessageProcess(update.editedMessage()); - } - - private boolean editedMessageProcess (Message edited) { - if (edited.chat().id() != MornyCoeur.config().medicationNotifyToChat) return false; - MornyDaemons.medicationTimerInstance.refreshNotificationWrite(edited); - return true; - } - -} diff --git a/src/main/old/cc/sukazyo/cono/morny/bot/event/OnQuestionMarkReply.java b/src/main/old/cc/sukazyo/cono/morny/bot/event/OnQuestionMarkReply.java deleted file mode 100644 index 8e51eeb..0000000 --- a/src/main/old/cc/sukazyo/cono/morny/bot/event/OnQuestionMarkReply.java +++ /dev/null @@ -1,38 +0,0 @@ -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 com.pengrad.telegrambot.request.SendMessage; - -import javax.annotation.Nonnull; -import java.util.Set; - -import static cc.sukazyo.cono.morny.util.CommonRandom.probabilityTrue; - -public class OnQuestionMarkReply extends EventListener { - - /** - * 一个 unicode 的问号字符列表. 不仅有半角全角问号,也包含了变体问号,和叹号结合的问好以及 uni-emoji 问号。 - * @since 1.0.0-RC3.2 - */ - public static final Set QUESTION_MARKS = Set.of('?', '?', '¿', '⁈', '⁇', '‽', '❔', '❓'); - - @Override - public boolean onMessage (@Nonnull Update update) { - - if (update.message().text() == null) return false; - - if (!probabilityTrue(8)) return false; - for (char c : update.message().text().toCharArray()) { - if (!QUESTION_MARKS.contains(c)) return false; - } - - MornyCoeur.extra().exec(new SendMessage( - update.message().chat().id(), update.message().text() - ).replyToMessageId(update.message().messageId())); - return true; - - } - -} diff --git a/src/main/old/cc/sukazyo/cono/morny/bot/event/OnRandomlyTriggered.java b/src/main/old/cc/sukazyo/cono/morny/bot/event/OnRandomlyTriggered.java index 5481a08..24c8c2b 100644 --- a/src/main/old/cc/sukazyo/cono/morny/bot/event/OnRandomlyTriggered.java +++ b/src/main/old/cc/sukazyo/cono/morny/bot/event/OnRandomlyTriggered.java @@ -2,7 +2,8 @@ package cc.sukazyo.cono.morny.bot.event; import cc.sukazyo.cono.morny.bot.api.EventListener; -public class OnRandomlyTriggered extends EventListener { +@Deprecated +public class OnRandomlyTriggered implements EventListener { // /** // * function CODE_IK0XA1 diff --git a/src/main/old/cc/sukazyo/cono/morny/bot/event/OnTelegramCommand.java b/src/main/old/cc/sukazyo/cono/morny/bot/event/OnTelegramCommand.java deleted file mode 100644 index a74e7a5..0000000 --- a/src/main/old/cc/sukazyo/cono/morny/bot/event/OnTelegramCommand.java +++ /dev/null @@ -1,30 +0,0 @@ -package cc.sukazyo.cono.morny.bot.event; - -import cc.sukazyo.cono.morny.MornyCoeur; -import cc.sukazyo.cono.morny.bot.api.EventListener; -import cc.sukazyo.cono.morny.util.tgapi.InputCommand; - -import com.pengrad.telegrambot.model.Update; - -import javax.annotation.Nonnull; - -import static cc.sukazyo.cono.morny.Log.logger; - -public class OnTelegramCommand extends EventListener { - - @Override - public boolean onMessage (@Nonnull Update event) { - if (event.message().text() == null || !event.message().text().startsWith("/") || event.message().text().startsWith("/ ")) { - logger.debug("not command"); - return false; // 检测到非(命令格式)文本,忽略掉命令处理 - } - final InputCommand command = new InputCommand(event.message().text().substring(1)); - if (!command.getCommand().matches("^\\w+$")) { logger.debug("not command");return false; } - logger.debug("is command"); - if (command.getTarget() != null && !MornyCoeur.getUsername().equals(command.getTarget())) { - return true; // 检测到命令并非针对 morny,退出整个事件处理链 - } - return MornyCoeur.commandManager().execute(command, event); // 转交命令管理器执行命令 - } - -} diff --git a/src/main/old/cc/sukazyo/cono/morny/bot/event/OnUniMeowTrigger.java b/src/main/old/cc/sukazyo/cono/morny/bot/event/OnUniMeowTrigger.java deleted file mode 100644 index 59e8be1..0000000 --- a/src/main/old/cc/sukazyo/cono/morny/bot/event/OnUniMeowTrigger.java +++ /dev/null @@ -1,36 +0,0 @@ -package cc.sukazyo.cono.morny.bot.event; - -import cc.sukazyo.cono.morny.bot.api.EventListener; -import cc.sukazyo.cono.morny.bot.command.ISimpleCommand; -import cc.sukazyo.cono.morny.util.tgapi.InputCommand; -import com.pengrad.telegrambot.model.Update; - -import javax.annotation.Nonnull; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.atomic.AtomicBoolean; - -public class OnUniMeowTrigger extends EventListener { - - private static final Map triggers = new HashMap<>(); - - public static void register (ISimpleCommand... list) { - for (ISimpleCommand cmd : list) - triggers.put(cmd.getName(), cmd); - } - - @Override - public boolean onMessage (@Nonnull Update event) { - if (event.message().text() == null) return false; - AtomicBoolean ok = new AtomicBoolean(false); - triggers.forEach((name, command) -> { - name = "/" + name; - if (name.equals(event.message().text())) { - command.execute(new InputCommand(name), event); - ok.set(true); - } - }); - return ok.get(); - } - -} diff --git a/src/main/old/cc/sukazyo/cono/morny/bot/event/OnUpdateTimestampOffsetLock.java b/src/main/old/cc/sukazyo/cono/morny/bot/event/OnUpdateTimestampOffsetLock.java deleted file mode 100644 index faee77f..0000000 --- a/src/main/old/cc/sukazyo/cono/morny/bot/event/OnUpdateTimestampOffsetLock.java +++ /dev/null @@ -1,56 +0,0 @@ -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 javax.annotation.Nonnull; - -/** - * 阻止 {@link cc.sukazyo.cono.morny.MornyConfig#eventOutdatedTimestamp 指定时间} 之前的事件处理. - *

- * 只支持以下事件 - *

    - *
  • {@link EventListener#onMessage(Update) 收到消息}
  • - *
  • {@link EventListener#onEditedMessage(Update) 消息被更新}
  • - *
  • {@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.config().eventOutdatedTimestamp/1000; - } - - @Override - public boolean onMessage (@Nonnull Update update) { - return isOutdated(update.message().date()); - } - - /** @since 0.4.2.6 */ - @Override - public boolean onEditedMessage (@Nonnull Update update) { - return isOutdated(update.editedMessage().editDate()); - } - - /** @since 0.4.2.6 */ - @Override - public boolean onChannelPost (@Nonnull Update update) { - return isOutdated(update.channelPost().date()); - } - - /** @since 0.4.2.6 */ - @Override - public boolean onEditedChannelPost (@Nonnull Update update) { - return isOutdated(update.editedChannelPost().editDate()); - } - -} diff --git a/src/main/old/cc/sukazyo/cono/morny/daemon/MornyReport.java b/src/main/old/cc/sukazyo/cono/morny/daemon/MornyReport.java index 9a81a5e..8f49964 100644 --- a/src/main/old/cc/sukazyo/cono/morny/daemon/MornyReport.java +++ b/src/main/old/cc/sukazyo/cono/morny/daemon/MornyReport.java @@ -37,7 +37,7 @@ public class MornyReport { } } - public static void exception (@Nonnull Exception e, @Nullable String description) { + public static void exception (@Nonnull Throwable e, @Nullable String description) { if (unsupported()) return; executeReport(new SendMessage( MornyCoeur.config().reportToChat, diff --git a/src/main/old/cc/sukazyo/cono/morny/data/MornyJrrp.java b/src/main/old/cc/sukazyo/cono/morny/data/MornyJrrp.java deleted file mode 100644 index 029e476..0000000 --- a/src/main/old/cc/sukazyo/cono/morny/data/MornyJrrp.java +++ /dev/null @@ -1,46 +0,0 @@ -package cc.sukazyo.cono.morny.data; - -import cc.sukazyo.cono.morny.util.CommonConvert; -import cc.sukazyo.cono.morny.util.CommonEncrypt; -import com.pengrad.telegrambot.model.User; - -/** - * Morny 的 jrrp 运算类. - * - * @see #getJrrpFromTelegramUser(User,long) - * @see #calcJrrpXmomi(long,long) - * @since 0.4.2.9 - */ -public class MornyJrrp { - - /** - * 通过 telegram 用户和时间戳作为参数获取 jrrp. - * - * @see #calcJrrpXmomi 当前版本的实现算法 {@code Xmomi} - * @since 0.4.2.9 - * @param user telegram 用户 - * @param timestamp 时间戳 - * @return 通过当前版本的算法计算出的用户 jrrp 值,取值为 {@code [0.00, 100.00]} - */ - public static double getJrrpFromTelegramUser (User user, long timestamp) { - return calcJrrpXmomi(user.id(), timestamp / (1000 * 60 * 60 * 24)) * 100.0; - } - - /** - * {@code Xmomi} 版本的 jrrp 算法. - *

- * 算法规则为,将用户id与日期戳链接为 uid@daystamp 这样的字符串, - * 然后通过 MD5 计算出字符串的哈希值,取哈希值前4个字节,将其作为16进制数值表示法转换为取值为 {@code [0x0000, 0xffff]} 的数值, - * 得到的数值除以区间最大值 {@code 0xffff} 即可得到一个分布在 {@code [0.0, 1.0]} 之间的分布值, - * 这个分布值乘以 {@code 100.0},即为计算得到的 jrrp 数值。 - * - * @since 0.4.2.9 - * @param userId telegram 用户 uid - * @param dayStamp unix 时间戳转换为日期单位后的数值. 数值应该在转换前转换时区 - * @return 算法得到的 jrrp 值,取值为 {@code [0.00. 100.00]} - */ - public static double calcJrrpXmomi (long userId, long dayStamp) { - return (double)Long.parseLong(CommonConvert.byteArrayToHex(CommonEncrypt.hashMd5(userId + "@" + dayStamp)).substring(0, 4), 16) / (double)0xffff; - } - -} diff --git a/src/main/old/cc/sukazyo/cono/morny/data/NbnhhshQuery.java b/src/main/old/cc/sukazyo/cono/morny/data/NbnhhshQuery.java deleted file mode 100644 index 2ed6657..0000000 --- a/src/main/old/cc/sukazyo/cono/morny/data/NbnhhshQuery.java +++ /dev/null @@ -1,47 +0,0 @@ -package cc.sukazyo.cono.morny.data; - -import java.io.IOException; - -import com.google.gson.Gson; - -import cc.sukazyo.cono.morny.util.OkHttpPublic.MediaTypes; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.ResponseBody; - -public class NbnhhshQuery { - - public static class Word { - public String name; - public String[] trans; - public String[] inputting; - } - - public static class GuessResult { - public Word[] words; - } - - public record GuessReq (String text) {} - - public static final String API_URL = "https://lab.magiconch.com/api/nbnhhsh/"; - public static final String API_GUESS_METHOD = "guess/"; - - private static final OkHttpClient httpClient = new OkHttpClient(); - - public static GuessResult sendGuess (String text) throws IOException { - final String reqJsonText = new Gson().toJson(new GuessReq(text)); - Request request = new Request.Builder() - .url(API_URL + API_GUESS_METHOD) - .post(RequestBody.create(reqJsonText, MediaTypes.JSON)) - .build(); - try (Response response = httpClient.newCall(request).execute()) { - final ResponseBody body = response.body(); - if (body == null) throw new IOException("Null body."); - final String x = "{ \"words\": " + body.string() + " }"; - return new Gson().fromJson(x, GuessResult.class); - } - } - -} diff --git a/src/main/old/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromChat.java b/src/main/old/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromChat.java index 46045f0..e327279 100644 --- a/src/main/old/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromChat.java +++ b/src/main/old/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromChat.java @@ -1,10 +1,15 @@ package cc.sukazyo.cono.morny.util.tgapi.formatting; import com.pengrad.telegrambot.model.Chat; -import com.pengrad.telegrambot.model.Message; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; public class TGToStringFromChat { + + public static final long MASK_BOTAPI_ID = -1000000000000L; + private final Chat data; public TGToStringFromChat(Chat chat) { @@ -20,4 +25,36 @@ public class TGToStringFromChat { (String.format("%s {%s}[%d]", data.title(), data.username(), data.id())); } + @Nonnull + public String getSafeName () { + if (data.type() == Chat.Type.Private) + return data.firstName() + (data.lastName()==null ? "" : " "+data.lastName()); + else return data.title(); + } + + @Nullable + public String getSafeLinkHTML () { + if (data.username() == null) { + if (data.type() == Chat.Type.Private) + // language=html + return String.format("@[u:%d]", data.id(), data.id()); + // language=html + else return String.format("@[c/%d]", id_tdLib(), id_tdLib()); + } else return "@"+data.username(); + } + + public long id_tdLib () { + return data.id() < 0 ? Math.abs(data.id() - MASK_BOTAPI_ID) : data.id(); + } + + @Nonnull + public String getTypeTag () { + return switch (data.type()) { + case Private -> "🔒"; + case group -> "💭"; + case supergroup -> "💬"; + case channel -> "📢"; + }; + } + } diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/api/EventListener.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/api/EventListener.scala new file mode 100644 index 0000000..67b7047 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/api/EventListener.scala @@ -0,0 +1,22 @@ +package cc.sukazyo.cono.morny.bot.api + +import com.pengrad.telegrambot.model.Update + +trait EventListener { + + def onMessage (using Update): Boolean = false + def onEditedMessage (using Update): Boolean = false + def onChannelPost (using Update): Boolean = false + def onEditedChannelPost (using Update): Boolean = false + def onInlineQuery (using Update): Boolean = false + def onChosenInlineResult (using Update): Boolean = false + def onCallbackQuery (using Update): Boolean = false + def onShippingQuery (using Update): Boolean = false + def onPreCheckoutQuery (using Update): Boolean = false + def onPoll (using Update): Boolean = false + def onPollAnswer (using Update): Boolean = false + def onMyChatMemberUpdated (using Update): Boolean = false + def onChatMemberUpdated (using Update): Boolean = false + def onChatJoinRequest (using Update): Boolean = false + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/api/EventListenerManager.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/api/EventListenerManager.scala new file mode 100644 index 0000000..9eed851 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/api/EventListenerManager.scala @@ -0,0 +1,84 @@ +package cc.sukazyo.cono.morny.bot.api + +import cc.sukazyo.cono.morny.Log +import cc.sukazyo.cono.morny.util.tgapi.event.EventRuntimeException +import cc.sukazyo.cono.morny.Log.{exceptionLog, logger} +import cc.sukazyo.cono.morny.daemon.MornyReport +import com.google.gson.GsonBuilder +import com.pengrad.telegrambot.model.Update + +import scala.collection.mutable +import scala.language.postfixOps + +object EventListenerManager { + + private val listeners = mutable.Queue.empty[EventListener] + + def register (listeners: EventListener*): Unit = + this.listeners ++= listeners + + private class EventRunner (using event: Update) extends Thread { + this setName s"evt-${event.updateId()}-nn" + private def updateThreadName (t: String): Unit = + this setName s"evt-${event.updateId()}-$t" + + override def run (): Unit = { + for (i <- listeners) { + object status: + var _status = 0 + def isOk: Boolean = _status > 0 + def check (u: Boolean): Unit = if u then _status = _status + 1 + try { + updateThreadName("message") + if event.message ne null then status check i.onMessage + updateThreadName("edited-message") + if event.editedMessage ne null then status check i.onEditedMessage + updateThreadName("channel-post") + if event.channelPost ne null then status check i.onChannelPost + updateThreadName("edited-channel-post") + if event.editedChannelPost ne null then status check i.onEditedChannelPost + updateThreadName("inline-query") + if event.inlineQuery ne null then status check i.onInlineQuery + updateThreadName("chosen-inline-result") + if event.chosenInlineResult ne null then status check i.onChosenInlineResult + updateThreadName("callback-query") + if event.callbackQuery ne null then status check i.onCallbackQuery + updateThreadName("shipping-query") + if event.shippingQuery ne null then status check i.onShippingQuery + updateThreadName("pre-checkout-query") + if event.preCheckoutQuery ne null then status check i.onPreCheckoutQuery + updateThreadName("poll") + if event.poll ne null then status check i.onPoll + updateThreadName("poll-answer") + if event.pollAnswer ne null then status check i.onPollAnswer + updateThreadName("my-chat-member") + if event.myChatMember ne null then status check i.onMyChatMemberUpdated + updateThreadName("chat-member") + if event.chatMember ne null then status check i.onChatMemberUpdated + updateThreadName("chat-join-request") + if event.chatJoinRequest ne null then status check i.onChatJoinRequest + } catch case e => { + val errorMessage = StringBuilder() + errorMessage ++= "Event throws unexpected exception:\n" + errorMessage ++= (exceptionLog(e) indent 4) + e match + case actionFailed: EventRuntimeException.ActionFailed => + errorMessage ++= "\ntg-api action: response track: " + errorMessage ++= (GsonBuilder().setPrettyPrinting().create().toJson( + actionFailed.getResponse + ) indent 4) ++= "\n" + case _ => + logger error errorMessage.toString + MornyReport.exception(e, "on event running") + } + if (status isOk) return + } + } + + } + + def publishUpdate (using Update): Unit = { + EventRunner().start() + } + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/api/TelegramUpdatesListener.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/api/TelegramUpdatesListener.scala new file mode 100644 index 0000000..83c2101 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/api/TelegramUpdatesListener.scala @@ -0,0 +1,17 @@ +package cc.sukazyo.cono.morny.bot.api + +import com.pengrad.telegrambot.UpdatesListener +import com.pengrad.telegrambot.model.Update + +import java.util +import scala.jdk.CollectionConverters.* + +object TelegramUpdatesListener extends UpdatesListener { + + override def process (updates: util.List[Update]): Int = { + for (update <- updates.asScala) + EventListenerManager.publishUpdate(using update) + UpdatesListener.CONFIRMED_UPDATES_ALL + } + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/command/DirectMsgClear.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/command/DirectMsgClear.scala index e3e1761..a2e38b7 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/command/DirectMsgClear.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/DirectMsgClear.scala @@ -11,10 +11,10 @@ import scala.language.postfixOps object DirectMsgClear extends ISimpleCommand { - override def getName: String = "r" - override def getAliases: Array[String] = null + override val name: String = "r" + override val aliases: Array[ICommandAlias] | Null = null - override def execute (command: InputCommand, event: Update): Unit = { + override def execute (using command: InputCommand, event: Update): Unit = { logger debug "executing command /r" if (event.message.replyToMessage == null) return; diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/command/Encryptor.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/command/Encryptor.scala index 77be888..8bb3987 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/command/Encryptor.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/Encryptor.scala @@ -18,12 +18,12 @@ import scala.language.postfixOps object Encryptor extends ITelegramCommand { - override def getName: String = "encrypt" - override def getAliases: Array[String] = null - override def getParamRule: String = "[algorithm|(l)] [(uppercase)]" - override def getDescription: String = "通过指定算法加密回复的内容 (目前只支持文本)" + override val name: String = "encrypt" + override val aliases: Array[ICommandAlias] | Null = null + override val paramRule: String = "[algorithm|(l)] [(uppercase)]" + override val description: String = "通过指定算法加密回复的内容 (目前只支持文本)" - override def execute (command: InputCommand, event: Update): Unit = { + override def execute (using command: InputCommand, event: Update): Unit = { val args = command.getArgs diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/command/EventHack.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/command/EventHack.scala index a4fddb0..6118412 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/command/EventHack.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/EventHack.scala @@ -11,12 +11,12 @@ import scala.language.postfixOps object EventHack extends ITelegramCommand { - override def getName: String = "event_hack" - override def getAliases: Array[String] = null - override def getParamRule: String = "[(user|group|any)]" - override def getDescription: String = "输出 bot 下一个获取到的事件序列化数据" + override val name: String = "event_hack" + override val aliases: Array[ICommandAlias] | Null = null + override val paramRule: String = "[(user|group|any)]" + override val description: String = "输出 bot 下一个获取到的事件序列化数据" - override def execute (command: InputCommand, event: Update): Unit = { + override def execute (using command: InputCommand, event: Update): Unit = { val x_mode = if (command.hasArgs) command.getArgs()(0) else "" diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/command/GetUsernameAndId.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/command/GetUsernameAndId.scala index 3f03650..f4c414b 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/command/GetUsernameAndId.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/GetUsernameAndId.scala @@ -1,7 +1,8 @@ package cc.sukazyo.cono.morny.bot.command + import cc.sukazyo.cono.morny.MornyCoeur -import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramUserInformation import cc.sukazyo.cono.morny.util.tgapi.{InputCommand, Standardize} +import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramUserInformation import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.model.request.ParseMode import com.pengrad.telegrambot.request.{GetChatMember, SendMessage} @@ -10,12 +11,12 @@ import scala.language.postfixOps object GetUsernameAndId extends ITelegramCommand { - override def getName: String = "user" - override def getAliases: Array[String] = Array() - override def getParamRule: String = "[userid]" - override def getDescription: String = "获取指定或回复的用户相关信息" + override val name: String = "user" + override val aliases: Array[ICommandAlias] | Null = null + override val paramRule: String = "[userid]" + override val description: String = "获取指定或回复的用户相关信息" - override def execute (command: InputCommand, event: Update): Unit = { + override def execute (using command: InputCommand, event: Update): Unit = { val args = command.getArgs @@ -49,7 +50,7 @@ object GetUsernameAndId extends ITelegramCommand { val user = response.chatMember.user - if (user.id eq Standardize.CHANNEL_SPEAKER_MAGIC_ID) + if (user.id == Standardize.CHANNEL_SPEAKER_MAGIC_ID) MornyCoeur.extra exec SendMessage( event.message.chat.id, "$__channel_identify" diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/command/ICommandAlias.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/command/ICommandAlias.scala new file mode 100644 index 0000000..749f550 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/ICommandAlias.scala @@ -0,0 +1,18 @@ +package cc.sukazyo.cono.morny.bot.command + +trait ICommandAlias { + + val name: String + val listed: Boolean + +} + +object ICommandAlias { + + case class ListedAlias (name: String) extends ICommandAlias: + override val listed = true + + case class HiddenAlias (name: String) extends ICommandAlias: + override val listed = false + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/command/IP186Query.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/command/IP186Query.scala index a901580..5d78ea1 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/command/IP186Query.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/IP186Query.scala @@ -16,19 +16,19 @@ object IP186Query { case WHOIS extends Subs("whois") object IP extends ITelegramCommand: - override def getName: String = "ip" - override def getAliases: Array[String] = null - override def getParamRule: String = "[ip]" - override def getDescription: String = "通过 https://ip.186526.xyz 查询 ip 资料" - override def execute (command: InputCommand, event: Update): Unit = query(event, command) + override val name: String = "ip" + override val aliases: Array[ICommandAlias]|Null = null + override val paramRule: String = "[ip]" + override val description: String = "通过 https://ip.186526.xyz 查询 ip 资料" + override def execute (using command: InputCommand, event: Update): Unit = query object Whois extends ITelegramCommand: - override def getName: String = "whois" - override def getAliases: Array[String] = null - override def getParamRule: String = "[domain]" - override def getDescription: String = "通过 https://ip.186526.xyz 查询域名资料" - override def execute (command: InputCommand, event: Update): Unit = query(event, command) + override val name: String = "whois" + override val aliases: Array[ICommandAlias]|Null = null + override val paramRule: String = "[domain]" + override val description: String = "通过 https://ip.186526.xyz 查询域名资料" + override def execute (using command: InputCommand, event: Update): Unit = query - private def query (event: Update, command: InputCommand): Unit = { + private def query (using event: Update, command: InputCommand): Unit = { val target: String|Null = if (command.getArgs isEmpty) diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/command/ISimpleCommand.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/command/ISimpleCommand.scala new file mode 100644 index 0000000..25181bd --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/ISimpleCommand.scala @@ -0,0 +1,13 @@ +package cc.sukazyo.cono.morny.bot.command + +import cc.sukazyo.cono.morny.util.tgapi.InputCommand +import com.pengrad.telegrambot.model.Update + +trait ISimpleCommand { + + val name: String + val aliases: Array[ICommandAlias]|Null + + def execute (using command: InputCommand, event: Update): Unit + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/command/ITelegramCommand.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/command/ITelegramCommand.scala new file mode 100644 index 0000000..2c16263 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/ITelegramCommand.scala @@ -0,0 +1,8 @@ +package cc.sukazyo.cono.morny.bot.command + +trait ITelegramCommand extends ISimpleCommand { + + val paramRule: String + val description: String + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyCommands.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyCommands.scala new file mode 100644 index 0000000..7fa9876 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyCommands.scala @@ -0,0 +1,111 @@ +package cc.sukazyo.cono.morny.bot.command + +import cc.sukazyo.cono.morny.util.tgapi.InputCommand +import cc.sukazyo.cono.morny.MornyCoeur +import cc.sukazyo.cono.morny.data.TelegramStickers +import com.pengrad.telegrambot.model.{BotCommand, DeleteMyCommands, Update} +import com.pengrad.telegrambot.request.{SendSticker, SetMyCommands} + +import scala.collection.{mutable, SeqMap} +import scala.collection.mutable.ArrayBuffer +import scala.language.postfixOps +import cc.sukazyo.cono.morny.Log.logger + +object MornyCommands { + + private type CommandMap = SeqMap[String, ISimpleCommand] + private def CommandMap (commands: ISimpleCommand*): CommandMap = + val stash: mutable.SeqMap[String, ISimpleCommand] = mutable.SeqMap() + for (i <- commands) stash += ((i.name, i)) + stash + + private val commands: CommandMap = CommandMap( + + MornyHellos.On, + MornyHellos.On, + MornyHellos.Hello, + MornyInfoOnStart, + GetUsernameAndId, + EventHack, + Nbnhhsh, + IP186Query.IP, + IP186Query.Whois, + Encryptor, + MornyManagers.SaveData, + MornyInformation, + MornyInformationOlds.Version, + MornyInformationOlds.Runtime, + MornyOldJrrp, + MornyManagers.Exit, + + Testing, + DirectMsgClear, + + 私わね, + 喵呜.Progynova + + ) + + @SuppressWarnings(Array("NonAsciiCharacters")) + val commands_uni: CommandMap = CommandMap( + 喵呜.抱抱, + 喵呜.揉揉, + 喵呜.贴贴, + 喵呜.蹭蹭 + ) + + def execute (using command: InputCommand, event: Update): Boolean = { + if (commands contains command.getCommand) + commands(command.getCommand) execute; + true + else nonCommandExecutable + } + + private def nonCommandExecutable (using command: InputCommand, event: Update): Boolean = { + if command.getTarget eq null then false + else + MornyCoeur.extra exec SendSticker( + event.message.chat.id, + TelegramStickers ID_404 + ).replyToMessageId(event.message.messageId) + true + } + + def automaticTGListUpdate (): Unit = { + val listing = commands_toTelegramList + automaticTGListRemove() + MornyCoeur.extra exec SetMyCommands(listing:_*) + logger info + s"""automatic updated telegram command list : + |${commandsTelegramList_toString(listing)}""".stripMargin + } + + def automaticTGListRemove (): Unit = { + MornyCoeur.extra exec DeleteMyCommands() + logger info "cleaned up command list" + } + + private def commandsTelegramList_toString (list: Array[BotCommand]): String = + val builder = StringBuilder() + for (single <- list) + builder ++= s"${single.command} - ${single.description}\n" + (builder dropRight 1) toString + + private def commands_toTelegramList: Array[BotCommand] = + val list = ArrayBuffer.empty[BotCommand] + for ((name, command) <- commands) command match + case telegramCommand: ITelegramCommand if name == command.name => + list ++= formatTelegramCommandListLine(telegramCommand) + case _ => + list toArray + + private def formatTelegramCommandListLine (command: ITelegramCommand): Array[BotCommand] = + def buildOne (name: String, paramRule: String, intro: String): BotCommand = + BotCommand(name, if paramRule isBlank then intro else s"$paramRule - $intro") + val list = mutable.ArrayBuffer[BotCommand]( + buildOne(command.name, command.paramRule, command.description)) + if (command.aliases ne null) for (alias <- command.aliases) + if (alias.listed) list += buildOne(alias.name, "", "↑") + list toArray + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyHellos.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyHellos.scala new file mode 100644 index 0000000..ea310dc --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyHellos.scala @@ -0,0 +1,43 @@ +package cc.sukazyo.cono.morny.bot.command +import cc.sukazyo.cono.morny.util.tgapi.InputCommand +import cc.sukazyo.cono.morny.MornyCoeur +import cc.sukazyo.cono.morny.bot.command.ICommandAlias.ListedAlias +import cc.sukazyo.cono.morny.data.TelegramStickers +import com.pengrad.telegrambot.model.Update +import com.pengrad.telegrambot.request.SendSticker + +import scala.language.postfixOps + +object MornyHellos { + + object On extends ITelegramCommand { + + override val name: String = "on" + override val aliases: Array[ICommandAlias] | Null = null + override val paramRule: String = "" + override val description: String = "检查是否在线" + + override def execute (using command: InputCommand, event: Update): Unit = + MornyCoeur.extra exec SendSticker( + event.message.chat.id, + TelegramStickers ID_ONLINE_STATUS_RETURN + ).replyToMessageId(event.message.messageId) + + } + + object Hello extends ITelegramCommand { + + override val name: String = "hello" + override val aliases: Array[ICommandAlias] | Null = Array(ListedAlias("hi")) + override val paramRule: String = "" + override val description: String = "打招呼" + + override def execute (using command: InputCommand, event: Update): Unit = + MornyCoeur.extra exec SendSticker( + event.message.chat.id, + TelegramStickers ID_HELLO + ).replyToMessageId(event.message.messageId) + + } + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyInfoOnHello.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyInfoOnStart.scala similarity index 79% rename from src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyInfoOnHello.scala rename to src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyInfoOnStart.scala index 2df1ba5..8a9b101 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyInfoOnHello.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyInfoOnStart.scala @@ -8,12 +8,12 @@ import com.pengrad.telegrambot.request.SendPhoto import scala.language.postfixOps -object MornyInfoOnHello extends ISimpleCommand { +object MornyInfoOnStart extends ISimpleCommand { - override def getName: String = "start" - override def getAliases: Array[String] = Array() + override val name: String = "start" + override val aliases: Array[ICommandAlias] | Null = null - override def execute (command: InputCommand, event: Update): Unit = { + override def execute (using command: InputCommand, event: Update): Unit = { MornyCoeur.extra exec new SendPhoto( event.message.chat.id, diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyInformation.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyInformation.scala index e81a9fb..9b3dae3 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyInformation.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyInformation.scala @@ -23,12 +23,12 @@ object MornyInformation extends ITelegramCommand { val VERSION_2 = "v" } - override def getName: String = "info" - override def getAliases: Array[String] = Array() - override def getParamRule: String = "[(version|runtime|stickers[.IDs])]" - override def getDescription: String = "输出当前 Morny 的各种信息" + override val name: String = "info" + override val aliases: Array[ICommandAlias]|Null = null + override val paramRule: String = "[(version|runtime|stickers[.IDs])]" + override val description: String = "输出当前 Morny 的各种信息" - override def execute (command: InputCommand, event: Update): Unit = { + override def execute (using command: InputCommand, event: Update): Unit = { if (!command.hasArgs) { echoInfo(event.message.chat.id, event.message.messageId) @@ -38,10 +38,10 @@ object MornyInformation extends ITelegramCommand { val action: String = command.getArgs()(0) action match { - case Subs.STICKERS => echoStickers(command, event) - case Subs.RUNTIME => echoRuntime(event) - case Subs.VERSION | Subs.VERSION_2 => echoVersion(event) - case _ => echo404(event) + case Subs.STICKERS => echoStickers + case Subs.RUNTIME => echoRuntime + case Subs.VERSION | Subs.VERSION_2 => echoVersion + case _ => echo404 } } @@ -92,11 +92,11 @@ object MornyInformation extends ITelegramCommand { ).parseMode(ParseMode HTML).replyToMessageId(replyTo) } - private def echoStickers (command: InputCommand, event: Update): Unit = { + private def echoStickers (using command: InputCommand, event: Update): Unit = { val chat = event.message.chat.id val replyTo = event.message.messageId var sid: String|Null = null - if (command.getArgs()(0) eq Subs.STICKERS) { + if (command.getArgs()(0) == Subs.STICKERS) { if (command.getArgs.length == 1) sid = "" else if (command.getArgs.length == 2) sid = command.getArgs()(1) } else if (command.getArgs.length == 1) { @@ -104,7 +104,7 @@ object MornyInformation extends ITelegramCommand { sid = command.getArgs()(0) substring Subs.STICKERS.length+1 } } - if (sid == null) echo404(event) + if (sid == null) echo404 else echoStickers(sid, chat, replyTo) } @@ -113,11 +113,12 @@ object MornyInformation extends ITelegramCommand { else TelegramStickers echoStickerByID(sid, MornyCoeur.extra, send_chat, send_replyTo) } - private[command] def echoVersion (event: Update): Unit = { + private[command] def echoVersion (using event: Update): Unit = { val versionDeltaHTML = if (MornySystem.isUseDelta) s"-δ${h(MornySystem.VERSION_DELTA)}" else "" val versionGitHTML = if (MornySystem.isGitBuild) s"git $getVersionGitTagHTML" else "" MornyCoeur.extra exec new SendMessage( event.message.chat.id, + // language=html s"""version: |- Morny ${h(MornySystem.CODENAME toUpperCase)} |- ${h(MornySystem.VERSION_BASE)}$versionDeltaHTML${if (MornySystem.isGitBuild) "\n- " + versionGitHTML else ""} @@ -130,11 +131,11 @@ object MornyInformation extends ITelegramCommand { ).replyToMessageId(event.message.messageId).parseMode(ParseMode HTML) } - private[command] def echoRuntime (event: Update): Unit = { + private[command] def echoRuntime (using event: Update): Unit = { def sysprop (p: String): String = System.getProperty(p) MornyCoeur.extra exec new SendMessage( event.message.chat.id, - /* html */ + /* language=html */ s"""system: |- Morny ${h(if (getRuntimeHostname == null) "" else getRuntimeHostname)} |- ${h(sysprop("os.name"))} ${h(sysprop("os.arch"))} ${h(sysprop("os.version"))} @@ -158,7 +159,7 @@ object MornyInformation extends ITelegramCommand { ).parseMode(ParseMode HTML).replyToMessageId(event.message.messageId) } - private def echo404 (event: Update): Unit = + private def echo404 (using event: Update): Unit = MornyCoeur.extra exec new SendSticker( event.message.chat.id, TelegramStickers ID_404 diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyInformationOlds.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyInformationOlds.scala new file mode 100644 index 0000000..6f44f16 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyInformationOlds.scala @@ -0,0 +1,17 @@ +package cc.sukazyo.cono.morny.bot.command +import cc.sukazyo.cono.morny.util.tgapi.InputCommand +import com.pengrad.telegrambot.model.Update + +object MornyInformationOlds { + + object Version extends ISimpleCommand: + override val name: String = "version" + override val aliases: Array[ICommandAlias] | Null = null + override def execute (using command: InputCommand, event: Update): Unit = MornyInformation.echoVersion + + object Runtime extends ISimpleCommand: + override val name: String = "runtime" + override val aliases: Array[ICommandAlias] | Null = null + override def execute (using command: InputCommand, event: Update): Unit = MornyInformation.echoRuntime + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyManagers.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyManagers.scala new file mode 100644 index 0000000..7218dc9 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyManagers.scala @@ -0,0 +1,86 @@ +package cc.sukazyo.cono.morny.bot.command +import cc.sukazyo.cono.morny.bot.command.ICommandAlias.HiddenAlias +import cc.sukazyo.cono.morny.util.tgapi.InputCommand +import cc.sukazyo.cono.morny.MornyCoeur +import cc.sukazyo.cono.morny.data.TelegramStickers +import cc.sukazyo.cono.morny.util.tgapi.formatting.TGToString +import com.pengrad.telegrambot.model.Update +import com.pengrad.telegrambot.request.SendSticker + +import scala.language.postfixOps +import cc.sukazyo.cono.morny.Log.logger +import cc.sukazyo.cono.morny.daemon.MornyReport + +object MornyManagers { + + object Exit extends ITelegramCommand { + + override val name: String = "exit" + override val aliases: Array[ICommandAlias] | Null = Array(HiddenAlias("stop"), HiddenAlias("quit")) + override val paramRule: String = "exit" + override val description: String = "关闭 Bot (仅可信成员)" + + override def execute (using command: InputCommand, event: Update): Unit = { + + val user = event.message.from + + if (MornyCoeur.trustedInstance isTrusted user.id) { + + MornyCoeur.extra exec SendSticker( + event.message.chat.id, + TelegramStickers ID_EXIT + ).replyToMessageId(event.message.messageId) + logger info s"Morny exited by user ${(TGToString as user) toStringLogTag}" + MornyCoeur.exit(0, user) + + } else { + + MornyCoeur.extra exec SendSticker( + event.message.chat.id, + TelegramStickers ID_403 + ).replyToMessageId(event.message.messageId) + logger info s"403 exit caught from user ${(TGToString as user) toStringLogTag}" + MornyReport.unauthenticatedAction("/exit", user) + + } + + } + + } + + object SaveData extends ITelegramCommand { + + override val name: String = "save" + override val aliases: Array[ICommandAlias] | Null = null + override val paramRule: String = "" + override val description: String = "保存缓存数据到文件(仅可信成员)" + + override def execute (using command: InputCommand, event: Update): Unit = { + + val user = event.message.from + + if (MornyCoeur.trustedInstance isTrusted user.id) { + + logger info s"call save from command by ${(TGToString as user) toStringLogTag}" + MornyCoeur.callSaveData() + MornyCoeur.extra exec SendSticker( + event.message.chat.id, + TelegramStickers ID_SAVED + ).replyToMessageId(event.message.messageId) + + } else { + + MornyCoeur.extra exec SendSticker( + event.message.chat.id, + TelegramStickers ID_403 + ).replyToMessageId(event.message.messageId) + logger info s"403 save caught from user ${(TGToString as user) toStringLogTag}" + MornyReport.unauthenticatedAction("/save", user) + + } + + } + + } + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyOldJrrp.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyOldJrrp.scala new file mode 100644 index 0000000..23fa2fa --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyOldJrrp.scala @@ -0,0 +1,36 @@ +package cc.sukazyo.cono.morny.bot.command +import cc.sukazyo.cono.morny.util.tgapi.InputCommand +import com.pengrad.telegrambot.model.Update +import cc.sukazyo.cono.morny.data.MornyJrrp +import cc.sukazyo.cono.morny.MornyCoeur +import cc.sukazyo.cono.morny.util.tgapi.formatting.TGToString +import com.pengrad.telegrambot.model.request.ParseMode +import com.pengrad.telegrambot.request.SendMessage + +import scala.language.postfixOps +object MornyOldJrrp extends ITelegramCommand { + + override val name: String = "jrrp" + override val aliases: Array[ICommandAlias] | Null = null + override val paramRule: String = "" + override val description: String = "获取 (假的) jrrp" + + override def execute (using command: InputCommand, event: Update): Unit = { + + val user = event.message.from + val jrrp = MornyJrrp.jrrp_of_telegramUser(user, System.currentTimeMillis) + val ending = jrrp match + case s if s > 70 => "!" + case a if a > 30 => ";" + case _ => "..." + + import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h + MornyCoeur.extra exec SendMessage( + event.message.chat.id, + // language=html + f"${(TGToString as user) fullnameRefHtml} 在(utc的)今天的运气指数是———— $jrrp%.2f%%${h(ending)}" + ).replyToMessageId(event.message.messageId).parseMode(ParseMode HTML) + + } + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/command/Nbnhhsh.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/command/Nbnhhsh.scala index 5c7d799..80c0c46 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/command/Nbnhhsh.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/Nbnhhsh.scala @@ -13,14 +13,16 @@ import scala.language.postfixOps object Nbnhhsh extends ITelegramCommand { - private val NBNHHSH_RESULT_HEAD_HTML = "## Result of nbnhhsh query :" + private val NBNHHSH_RESULT_HEAD_HTML = + // language=html + "## Result of nbnhhsh query :" - override def getName: String = "nbnhhsh" - override def getAliases: Array[String]|Null = null - override def getParamRule: String = "[text]" - override def getDescription: String = "检索文本内 nbnhhsh 词条" + override val name: String = "nbnhhsh" + override val aliases: Array[ICommandAlias]|Null = null + override val paramRule: String = "[text]" + override val description: String = "检索文本内 nbnhhsh 词条" - override def execute (command: InputCommand, event: Update): Unit = { + override def execute (using command: InputCommand, event: Update): Unit = { val queryTarget: String|Null = import cc.sukazyo.cono.morny.util.CommonConvert.stringsConnecting @@ -47,17 +49,17 @@ object Nbnhhsh extends ITelegramCommand { logger debug s"**xx len=${queryResp.words.length}" for (_word <- queryResp.words) { logger debug "**exec" - if ((_word.trans ne null) && (_word.trans isEmpty)) _word.trans = null - if ((_word.inputting ne null) && (_word.inputting isEmpty)) _word.inputting = null - if ((_word.trans ne null) || (_word.inputting ne null)) + val _use_trans = (_word.trans ne null) && (_word.trans nonEmpty) + val _use_inputting = (_word.inputting ne null) && (_word.inputting nonEmpty) + if (_use_trans || _use_inputting) message ++= s"\n\n[[ ${h(_word.name)} ]]" logger debug s"**used [${_word.name}]" - if (_word.trans != null) for (_trans <- _word.trans) + if (_use_trans) for (_trans <- _word.trans) message ++= s"\n* ${h(_trans)}" logger debug s"**used [${_word.name}] used `${_trans}``" - if (_word.inputting != null) + if (_use_inputting) logger debug s"**used [${_word.name}] inputting" - if (_word.trans != null) + if (_use_trans) message += '\n' message ++= " maybe:" for (_inputting <- _word.inputting) diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/command/Testing.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/command/Testing.scala index 4d453da..8316b42 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/command/Testing.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/Testing.scala @@ -12,17 +12,15 @@ import scala.language.postfixOps object Testing extends ISimpleCommand { - override def getName: String = "test" - override def getAliases: Array[String] = null + override val name: String = "test" + override val aliases: Array[ICommandAlias] | Null = null - override def execute (command: InputCommand, event: Update): Unit = { - - val a = StringBuilder("value") - a ++= "Changed" + override def execute (using command: InputCommand, event: Update): Unit = { MornyCoeur.extra exec new SendMessage( event.message.chat.id, - "Just a TEST command. num is:" + (a toString) + // language=html + "Just a TEST command." ).replyToMessageId(event.message.messageId).parseMode(ParseMode HTML) } diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/command/喵呜.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/command/喵呜.scala index c870e8e..bf36bab 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/command/喵呜.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/喵呜.scala @@ -15,39 +15,39 @@ import scala.language.postfixOps object 喵呜 { object 抱抱 extends ISimpleCommand { - override def getName: String = "抱抱" - override def getAliases: Array[String] = Array() - override def execute (command: InputCommand, event: Update): Unit = - replyingSet(event, "贴贴", "贴贴") + override val name: String = "抱抱" + override val aliases: Array[ICommandAlias]|Null = null + override def execute (using command: InputCommand, event: Update): Unit = + replyingSet("贴贴", "贴贴") } object 揉揉 extends ISimpleCommand { - override def getName: String = "揉揉" - override def getAliases: Array[String] = Array() - override def execute (command: InputCommand, event: Update): Unit = - replyingSet(event, "蹭蹭", "摸摸") + override val name: String = "揉揉" + override val aliases: Array[ICommandAlias]|Null = null + override def execute (using command: InputCommand, event: Update): Unit = + replyingSet("蹭蹭", "摸摸") } object 蹭蹭 extends ISimpleCommand { - override def getName: String = "蹭蹭" - override def getAliases: Array[String] = Array() - override def execute (command: InputCommand, event: Update): Unit = - replyingSet(event, "揉揉", "蹭蹭") + override val name: String = "蹭蹭" + override val aliases: Array[ICommandAlias]|Null = null + override def execute (using command: InputCommand, event: Update): Unit = + replyingSet("揉揉", "蹭蹭") } object 贴贴 extends ISimpleCommand { - override def getName: String = "贴贴" - override def getAliases: Array[String] = Array() - override def execute (command: InputCommand, event: Update): Unit = - replyingSet(event, "贴贴", "贴贴") + override val name: String = "贴贴" + override val aliases: Array[ICommandAlias]|Null = null + override def execute (using command: InputCommand, event: Update): Unit = + replyingSet("贴贴", "贴贴") } object Progynova extends ITelegramCommand { - override def getName: String = "install" - override def getAliases: Array[String] = Array() - override def getParamRule: String = "" - override def getDescription: String = "抽取一个神秘盒子" - override def execute (command: InputCommand, event: Update): Unit = { + override val name: String = "install" + override val aliases: Array[ICommandAlias]|Null = null + override val paramRule: String = "" + override val description: String = "抽取一个神秘盒子" + override def execute (using command: InputCommand, event: Update): Unit = { MornyCoeur.extra exec new SendSticker( event.message.chat.id, TelegramStickers ID_PROGYNOVA @@ -55,7 +55,7 @@ object 喵呜 { } } - private def replyingSet (event: Update, whileRec: String, whileNew: String): Unit = { + private def replyingSet (whileRec: String, whileNew: String)(using event: Update): Unit = { val isNew = event.message.replyToMessage == null; val target = if (isNew) event.message else event.message.replyToMessage MornyCoeur.extra exec new SendMessage( diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/command/私わね.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/command/私わね.scala index 67da3f5..0e249d4 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/command/私わね.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/私わね.scala @@ -8,10 +8,10 @@ import com.pengrad.telegrambot.request.SendMessage object 私わね extends ISimpleCommand { - override def getName: String = "me" - override def getAliases: Array[String] = Array() + override val name: String = "me" + override val aliases: Array[ICommandAlias] | Null = null - override def execute (command: InputCommand, event: Update): Unit = { + override def execute (using command: InputCommand, event: Update): Unit = { if (probabilityTrue(521)) { val text = "/打假" diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/event/MornyEventListeners.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/event/MornyEventListeners.scala new file mode 100644 index 0000000..4f39ac7 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/event/MornyEventListeners.scala @@ -0,0 +1,27 @@ +package cc.sukazyo.cono.morny.bot.event + +import cc.sukazyo.cono.morny.bot.api.EventListenerManager + +object MornyEventListeners { + + def registerAllEvents(): Unit = { + + EventListenerManager.register( + // ACTIVITY_RECORDER + OnUpdateTimestampOffsetLock, + // KUOHUANHUAN_NEED_SLEEP + OnTelegramCommand, + OnUniMeowTrigger, + OnUserRandom, + OnQuestionMarkReply, + OnUserSlashAction, + OnInlineQuery, + OnCallMe, + OnCallMsgSend, + OnMedicationNotifyApply, + OnEventHackHandle + ) + + } + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnCallMe.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnCallMe.scala index 1f51e4d..d8c334a 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnCallMe.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnCallMe.scala @@ -15,7 +15,7 @@ object OnCallMe extends EventListener { private val me = MornyCoeur.config.trustedMaster - override def onMessage (update: Update): Boolean = { + override def onMessage (using update: Update): Boolean = { if update.message.text == null then return false if update.message.chat.`type` != (Chat.Type Private) then return false diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnCallMsgSend.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnCallMsgSend.scala new file mode 100644 index 0000000..a6fee41 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnCallMsgSend.scala @@ -0,0 +1,153 @@ +package cc.sukazyo.cono.morny.bot.event + +import cc.sukazyo.cono.morny.bot.api.EventListener +import cc.sukazyo.cono.morny.MornyCoeur +import cc.sukazyo.cono.morny.data.TelegramStickers +import cc.sukazyo.cono.morny.util.tgapi.formatting.TGToString +import com.pengrad.telegrambot.model.{Chat, Message, MessageEntity, Update} +import com.pengrad.telegrambot.model.request.ParseMode +import com.pengrad.telegrambot.request.{GetChat, SendMessage, SendSticker} + +import scala.collection.mutable.ArrayBuffer +import scala.language.postfixOps +import scala.util.matching.Regex + +object OnCallMsgSend extends EventListener { + + private val REGEX_MSG_SENDREQ_DATA_HEAD: Regex = "^\\*msg(-?\\d+)(\\*\\S+)?(?:\\n([\\s\\S]+))?$"r + + case class MessageToSend ( + message: String|Null, + entities: Array[MessageEntity]|Null, + parseMode: ParseMode|Null, + targetId: Long + ) { + def toSendMessage (target_override: Long|Null = null): SendMessage = + val useTarget = if target_override == null then targetId else target_override + val sendMessage = SendMessage(useTarget, message) + if entities ne null then sendMessage.entities(entities:_*) + if parseMode ne null then sendMessage.parseMode(parseMode) + sendMessage + } + private object MessageToSend: + def from (raw: Message): MessageToSend = { + raw.text match + case REGEX_MSG_SENDREQ_DATA_HEAD(_target, _parseMode, _body) => + val target = _target toLong + val parseMode: ParseMode | Null = _parseMode match + case "*markdown" | "*md" | "*m↓" => ParseMode MarkdownV2 + case "*md1" => ParseMode Markdown + case "*html" => ParseMode HTML + case _ => null + val bodyOffset = "*msg".length + _target.length + (if _parseMode eq null then 0 else _parseMode.length) + 1 + val entities = ArrayBuffer.empty[MessageEntity] + if (raw.entities ne null) for (e <- raw.entities) + val _parsed = MessageEntity(e.`type`, e.offset - bodyOffset, e.length) + if e.url ne null then _parsed.url(e.url) + if e.user ne null then _parsed.user(e.user) + if e.language ne null then _parsed.language(e.language) + entities += _parsed + MessageToSend(_body, entities toArray, parseMode, target) + case _ => null + } + + override def onMessage (using update: Update): Boolean = { + + val message = update.message + + if message.chat.`type` != Chat.Type.Private then return false + if message.text eq null then return false + if !(message.text startsWith "*msg") then return false + + if (!(MornyCoeur.trustedInstance isTrusted message.from.id)) + MornyCoeur.extra exec SendSticker( + message.chat.id, + TelegramStickers ID_403 + ).replyToMessageId(message.messageId) + return true + + if (message.text == "*msgsend") { + + if (message.replyToMessage eq null) return answer404 + val messageToSend = MessageToSend from message.replyToMessage + if ((messageToSend eq null) || (messageToSend.message eq null)) return answer404 + val sendResponse = MornyCoeur.getAccount execute messageToSend.toSendMessage() + + if (sendResponse isOk) { + MornyCoeur.extra exec SendSticker( + update.message.chat.id, + TelegramStickers ID_SENT + ).replyToMessageId(update.message.messageId) + } else { + MornyCoeur.extra exec SendMessage( + update.message.chat.id, + // language=html + s"""${sendResponse.errorCode} FAILED + |${sendResponse.description}""" + .stripMargin + ).replyToMessageId(update.message.messageId).parseMode(ParseMode HTML) + } + + return true + + } + + val messageToSend: MessageToSend = + val raw: Message = + if (message.text == "*msg") + if message.replyToMessage eq null then return answer404 + else message.replyToMessage + else if (message.text startsWith "*msg") + message + else return answer404 + val _toSend = MessageToSend from raw + if _toSend eq null then return answer404 + else _toSend + + val targetChatResponse = MornyCoeur.getAccount execute GetChat(messageToSend.targetId) + if (targetChatResponse isOk) { + def getChatDescriptionHTML (chat: Chat): String = + import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h + val _c = TGToString as chat + // language=html + s"""${h(chat.id toString)}@${h(chat.`type`.name)}${if (chat.`type` != Chat.Type.Private) ":::" else ""} + |${_c getTypeTag} ${h(_c getSafeName)} ${_c getSafeLinkHTML}""" + .stripMargin + MornyCoeur.extra exec SendMessage( + update.message.chat.id, + getChatDescriptionHTML(targetChatResponse.chat) + ).parseMode(ParseMode HTML).replyToMessageId(update.message.messageId) + } else { + MornyCoeur.extra exec SendMessage( + update.message.chat.id, + // language=html + s"""${targetChatResponse.errorCode} FAILED + |${targetChatResponse.description}""" + .stripMargin + ).parseMode(ParseMode HTML).replyToMessageId(update.message.messageId) + } + + if messageToSend.message eq null then return true + val testSendResponse = MornyCoeur.getAccount execute messageToSend.toSendMessage(update.message.chat.id) + .replyToMessageId(update.message.messageId) + if (!(testSendResponse isOk)) + MornyCoeur.extra exec SendMessage( + update.message.chat.id, + // language=html + s"""${testSendResponse.errorCode} FAILED + |${testSendResponse.description}""" + .stripMargin + ).parseMode(ParseMode HTML).replyToMessageId(update.message.messageId) + + true + + } + + private def answer404 (using update: Update): Boolean = + MornyCoeur.extra exec SendSticker( + update.message.chat.id, + TelegramStickers ID_404 + ).replyToMessageId(update.message.messageId) + true + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnEventHackHandle.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnEventHackHandle.scala new file mode 100644 index 0000000..d618ddc --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnEventHackHandle.scala @@ -0,0 +1,80 @@ +package cc.sukazyo.cono.morny.bot.event + +import cc.sukazyo.cono.morny.bot.api.EventListener + +import scala.collection.mutable +import cc.sukazyo.cono.morny.Log.logger +import cc.sukazyo.cono.morny.MornyCoeur +import com.google.gson.GsonBuilder +import com.pengrad.telegrambot.model.Update +import com.pengrad.telegrambot.model.request.ParseMode +import com.pengrad.telegrambot.request.SendMessage + +import scala.language.postfixOps + +object OnEventHackHandle extends EventListener { + + private case class Hacker (from_chat: Long, from_message: Long): + override def toString: String = s"$from_chat/$from_message" + enum HackType: + case USER + case GROUP + case ANY + + private val hackers = mutable.HashMap.empty[String, Hacker] + + def registerHack (from_message: Long, from_user: Long, from_chat: Long, t: HackType): Unit = + val record = t match + case HackType.USER => s"(($from_user))" + case HackType.GROUP => s"{{$from_chat}}" + case HackType.ANY => "[[]]" + hackers += (record -> Hacker(from_chat, from_message)) + logger debug s"add hacker track $record" + + private def onEventHacked (chat: Long, fromUser: Long)(using update: Update): Boolean = { + logger debug s"got event signed {{$chat}}(($fromUser))" + val x: Hacker = + if hackers contains s"(($fromUser))" then (hackers remove s"(($fromUser))")get + else if hackers contains s"{{$chat}}" then (hackers remove s"{{$chat}}")get + else if hackers contains "[[]]" then (hackers remove "[[]]")get + else return false + logger debug s"hacked event by $x" + import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h + MornyCoeur.extra exec SendMessage( + x.from_chat, + // language=html + s"${h(GsonBuilder().setPrettyPrinting().create.toJson(update))}" + ).parseMode(ParseMode HTML).replyToMessageId(x.from_message toInt) + true + } + + override def onMessage (using update: Update): Boolean = + onEventHacked(update.message.chat.id, update.message.from.id) + override def onEditedMessage (using update: Update): Boolean = + onEventHacked(update.editedMessage.chat.id, update.editedMessage.from.id) + override def onChannelPost (using update: Update): Boolean = + onEventHacked(update.channelPost.chat.id, update.channelPost.from.id) + override def onEditedChannelPost (using update: Update): Boolean = + onEventHacked(update.editedChannelPost.chat.id, update.editedChannelPost.from.id) + override def onInlineQuery (using update: Update): Boolean = + onEventHacked(0, update.inlineQuery.from.id) + override def onChosenInlineResult (using update: Update): Boolean = + onEventHacked(0, update.chosenInlineResult.from.id) + override def onCallbackQuery (using update: Update): Boolean = + onEventHacked(0, update.callbackQuery.from.id) + override def onShippingQuery (using update: Update): Boolean = + onEventHacked(0, update.shippingQuery.from.id) + override def onPreCheckoutQuery (using update: Update): Boolean = + onEventHacked(0, update.preCheckoutQuery.from.id) + override def onPoll (using update: Update): Boolean = + onEventHacked(0, 0) + override def onPollAnswer (using update: Update): Boolean = + onEventHacked(0, update.pollAnswer.user.id) + override def onMyChatMemberUpdated (using update: Update): Boolean = + onEventHacked(update.myChatMember.chat.id, update.myChatMember.from.id) + override def onChatMemberUpdated (using update: Update): Boolean = + onEventHacked(update.chatMember.chat.id, update.chatMember.from.id) + override def onChatJoinRequest (using update: Update): Boolean = + onEventHacked(update.chatJoinRequest.chat.id, update.chatJoinRequest.from.id) + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnInlineQuery.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnInlineQuery.scala index 96f2ad0..970aa2d 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnInlineQuery.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnInlineQuery.scala @@ -1,7 +1,8 @@ package cc.sukazyo.cono.morny.bot.event import cc.sukazyo.cono.morny.MornyCoeur -import cc.sukazyo.cono.morny.bot.api.{EventListener, InlineQueryUnit} +import cc.sukazyo.cono.morny.bot.api.EventListener +import cc.sukazyo.cono.morny.bot.query.InlineQueryUnit import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.model.request.InlineQueryResult import com.pengrad.telegrambot.request.AnswerInlineQuery @@ -12,12 +13,12 @@ import scala.reflect.ClassTag object OnInlineQuery extends EventListener { - override def onInlineQuery (update: Update): Boolean = { + override def onInlineQuery (using update: Update): Boolean = { val results: List[InlineQueryUnit[_]] = MornyCoeur.queryManager query update var cacheTime = Int.MaxValue - var isPersonal = InlineQueryUnit.DEFAULT_INLINE_PERSONAL_RESP + var isPersonal = InlineQueryUnit.defaults.IS_PERSONAL val resultAnswers = ListBuffer[InlineQueryResult[_]]() for (r <- results) { if (cacheTime > r.cacheTime) cacheTime = r.cacheTime diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnMedicationNotifyApply.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnMedicationNotifyApply.scala new file mode 100644 index 0000000..5b2ab47 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnMedicationNotifyApply.scala @@ -0,0 +1,21 @@ +package cc.sukazyo.cono.morny.bot.event + +import cc.sukazyo.cono.morny.bot.api.EventListener +import cc.sukazyo.cono.morny.MornyCoeur +import cc.sukazyo.cono.morny.daemon.MornyDaemons +import com.pengrad.telegrambot.model.{Message, Update} + +object OnMedicationNotifyApply extends EventListener { + + override def onEditedMessage (using event: Update): Boolean = + editedMessageProcess(event.editedMessage) + override def onEditedChannelPost (using event: Update): Boolean = + editedMessageProcess(event.editedChannelPost) + + private def editedMessageProcess (edited: Message): Boolean = { + if edited.chat.id != MornyCoeur.config.medicationNotifyToChat then return false + MornyDaemons.medicationTimerInstance.refreshNotificationWrite(edited) + true + } + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnQuestionMarkReply.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnQuestionMarkReply.scala new file mode 100644 index 0000000..825f2d5 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnQuestionMarkReply.scala @@ -0,0 +1,30 @@ +package cc.sukazyo.cono.morny.bot.event + +import cc.sukazyo.cono.morny.bot.api.EventListener +import cc.sukazyo.cono.morny.MornyCoeur +import com.pengrad.telegrambot.model.Update +import com.pengrad.telegrambot.request.SendMessage + +import scala.language.postfixOps + +object OnQuestionMarkReply extends EventListener { + + private def QUESTION_MARKS = Set('?', '?', '¿', '⁈', '⁇', '‽', '❔', '❓') + + override def onMessage (using event: Update): Boolean = { + + if event.message.text eq null then return false + + import cc.sukazyo.cono.morny.util.CommonRandom.probabilityTrue + if !probabilityTrue(8) then return false + for (c <- event.message.text toCharArray) + if !(QUESTION_MARKS contains c) then return false + + MornyCoeur.extra exec SendMessage( + event.message.chat.id, event.message.text + ).replyToMessageId(event.message.messageId) + true + + } + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnTelegramCommand.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnTelegramCommand.scala new file mode 100644 index 0000000..526af48 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnTelegramCommand.scala @@ -0,0 +1,34 @@ +package cc.sukazyo.cono.morny.bot.event + +import cc.sukazyo.cono.morny.bot.api.EventListener +import cc.sukazyo.cono.morny.util.tgapi.InputCommand +import com.pengrad.telegrambot.model.{Message, Update} +import cc.sukazyo.cono.morny.Log.logger +import cc.sukazyo.cono.morny.MornyCoeur +import cc.sukazyo.cono.morny.bot.command.MornyCommands + +object OnTelegramCommand extends EventListener { + + override def onMessage (using update: Update): Boolean = { + + def _isCommandMessage(message: Message): Boolean = + if message.text eq null then false + else if !(message.text startsWith "/") then false + else if message.text startsWith "/ " then false + else true + + if !_isCommandMessage(update.message) then return false + val inputCommand = InputCommand(update.message.text drop 1) + if (!(inputCommand.getCommand matches "^\\w+$")) + logger debug "not command" + false + else if ((inputCommand.getTarget ne null) && (inputCommand.getTarget ne MornyCoeur.getUsername)) + logger debug "not morny command" + false + else + logger debug "is command" + MornyCommands.execute(using inputCommand) + + } + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnUniMeowTrigger.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnUniMeowTrigger.scala new file mode 100644 index 0000000..c482b63 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnUniMeowTrigger.scala @@ -0,0 +1,23 @@ +package cc.sukazyo.cono.morny.bot.event + +import cc.sukazyo.cono.morny.bot.api.EventListener +import cc.sukazyo.cono.morny.bot.command.MornyCommands +import cc.sukazyo.cono.morny.util.tgapi.InputCommand +import com.pengrad.telegrambot.model.Update + +object OnUniMeowTrigger extends EventListener { + + override def onMessage (using update: Update): Boolean = { + + if update.message.text eq null then return false + var ok = false + for ((name, command) <- MornyCommands.commands_uni) + val _name = "/"+name + if (_name == update.message.text) + command.execute(using InputCommand(_name)) + ok = true + ok + + } + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnUpdateTimestampOffsetLock.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnUpdateTimestampOffsetLock.scala new file mode 100644 index 0000000..a1978a8 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnUpdateTimestampOffsetLock.scala @@ -0,0 +1,17 @@ +package cc.sukazyo.cono.morny.bot.event + +import cc.sukazyo.cono.morny.bot.api.EventListener +import cc.sukazyo.cono.morny.MornyCoeur +import com.pengrad.telegrambot.model.Update + +object OnUpdateTimestampOffsetLock extends EventListener { + + private def isOutdated (timestamp: Int): Boolean = + timestamp < (MornyCoeur.config.eventOutdatedTimestamp/1000) + + override def onMessage (using update: Update): Boolean = isOutdated(update.message.date) + override def onEditedMessage (using update: Update): Boolean = isOutdated(update.editedMessage.date) + override def onChannelPost (using update: Update): Boolean = isOutdated(update.channelPost.date) + override def onEditedChannelPost (using update: Update): Boolean = isOutdated(update.editedChannelPost.date) + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnUserRandom.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnUserRandom.scala index 2e21f63..1657169 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnUserRandom.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnUserRandom.scala @@ -12,7 +12,7 @@ object OnUserRandom extends EventListener { private val USER_OR_QUERY = "(.+)(?:还是|or)(.+)"r private val USER_IF_QUERY = "(.+)[吗?|?]+$"r - override def onMessage(update: Update): Boolean = { + override def onMessage(using update: Update): Boolean = { if update.message.text == null then return false if update.message.text startsWith "/" then return false diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnUserSlashAction.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnUserSlashAction.scala index 1970726..9447a91 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnUserSlashAction.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnUserSlashAction.scala @@ -15,9 +15,9 @@ object OnUserSlashAction extends EventListener { private val TG_FORMAT = "^\\w+(@\\w+)?$"r - override def onMessage (update: Update): Boolean = { + override def onMessage (using update: Update): Boolean = { - val text = update.message.text; + val text = update.message.text if text == null then return false if (text startsWith "/") { @@ -31,6 +31,7 @@ object OnUserSlashAction extends EventListener { case TG_FORMAT(_) => return false case x if x contains "/" => return false + case _ => val isHardParse = actions(0) isBlank def hp_len(i: Int) = if isHardParse then i+1 else i @@ -39,7 +40,7 @@ object OnUserSlashAction extends EventListener { val hasObject = actions.length != hp_len(1) val v_object = if hasObject then - actions slice(hp_len(1), actions.length) mkString(" ") + actions slice(hp_len(1), actions.length) mkString " " else "" val origin = update.message val target = diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/query/ITelegramQuery.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/query/ITelegramQuery.scala index d03a05c..70c4739 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/query/ITelegramQuery.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/query/ITelegramQuery.scala @@ -1,7 +1,6 @@ package cc.sukazyo.cono.morny.bot.query import javax.annotation.Nullable -import cc.sukazyo.cono.morny.bot.api.InlineQueryUnit import com.pengrad.telegrambot.model.Update trait ITelegramQuery { diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/query/InlineQueryUnit.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/query/InlineQueryUnit.scala new file mode 100644 index 0000000..b15f4b6 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/query/InlineQueryUnit.scala @@ -0,0 +1,27 @@ +package cc.sukazyo.cono.morny.bot.query + +import cc.sukazyo.cono.morny.bot.query.InlineQueryUnit.defaults +import com.pengrad.telegrambot.model.request.InlineQueryResult + +object InlineQueryUnit { + + object defaults: + val CACHE_TIME = 300 + val IS_PERSONAL = false + +} + +class InlineQueryUnit[T <: InlineQueryResult[T]](val result: T) { + + var cacheTime: Int = defaults.CACHE_TIME + var isPersonal: Boolean = defaults.IS_PERSONAL + + def cacheTime (v: Int): InlineQueryUnit[T] = + this.cacheTime = v + this + + def isPersonal (v: Boolean): InlineQueryUnit[T] = + this.isPersonal = v + this + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/query/MornyQueries.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/query/MornyQueries.scala index faeaefb..5f13657 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/query/MornyQueries.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/query/MornyQueries.scala @@ -1,6 +1,5 @@ package cc.sukazyo.cono.morny.bot.query -import cc.sukazyo.cono.morny.bot.api.InlineQueryUnit import cc.sukazyo.cono.morny.bot.query import com.pengrad.telegrambot.model.Update diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/query/MyInformation.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/query/MyInformation.scala index c98feb6..14a4e81 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/query/MyInformation.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/query/MyInformation.scala @@ -1,6 +1,5 @@ package cc.sukazyo.cono.morny.bot.query -import cc.sukazyo.cono.morny.bot.api.InlineQueryUnit import cc.sukazyo.cono.morny.util.tgapi.formatting.NamedUtils.inlineIds import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramUserInformation import com.pengrad.telegrambot.model.Update diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/query/RawText.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/query/RawText.scala index 2d19149..aec52f6 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/query/RawText.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/query/RawText.scala @@ -1,5 +1,4 @@ package cc.sukazyo.cono.morny.bot.query -import cc.sukazyo.cono.morny.bot.api.InlineQueryUnit import cc.sukazyo.cono.morny.util.tgapi.formatting.NamedUtils.inlineIds import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.model.request.{InlineQueryResultArticle, InputTextMessageContent} diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/query/ShareToolBilibili.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/query/ShareToolBilibili.scala index 90288e2..bc1a4e7 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/query/ShareToolBilibili.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/query/ShareToolBilibili.scala @@ -1,7 +1,6 @@ package cc.sukazyo.cono.morny.bot.query import cc.sukazyo.cono.morny.Log.logger -import cc.sukazyo.cono.morny.bot.api.InlineQueryUnit import cc.sukazyo.cono.morny.util.BiliTool import cc.sukazyo.cono.morny.util.tgapi.formatting.NamedUtils.inlineIds import com.pengrad.telegrambot.model.Update diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/query/ShareToolTwitter.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/query/ShareToolTwitter.scala index 9427dca..ffc7f0e 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/query/ShareToolTwitter.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/query/ShareToolTwitter.scala @@ -1,6 +1,5 @@ package cc.sukazyo.cono.morny.bot.query -import cc.sukazyo.cono.morny.bot.api.InlineQueryUnit import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.model.request.InlineQueryResultArticle diff --git a/src/main/scala/cc/sukazyo/cono/morny/data/MornyJrrp.scala b/src/main/scala/cc/sukazyo/cono/morny/data/MornyJrrp.scala new file mode 100644 index 0000000..87f3364 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/data/MornyJrrp.scala @@ -0,0 +1,17 @@ +package cc.sukazyo.cono.morny.data + +import com.pengrad.telegrambot.model.User + +import scala.language.postfixOps + +object MornyJrrp { + + def jrrp_of_telegramUser (user: User, timestamp: Long): Double = + jrrp_v_xmomi(user.id, timestamp/(1000*60*60*24)) * 100.0 + + private def jrrp_v_xmomi (identifier: Long, dayStamp: Long): Double = + import cc.sukazyo.cono.morny.util.CommonConvert.byteArrayToHex + import cc.sukazyo.cono.morny.util.CommonEncrypt.hashMd5 + (java.lang.Long parseLong byteArrayToHex(hashMd5(s"$identifier@$dayStamp")).substring(0, 4)) / (0xffff toDouble) + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/data/NbnhhshQuery.scala b/src/main/scala/cc/sukazyo/cono/morny/data/NbnhhshQuery.scala new file mode 100644 index 0000000..9c2049a --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/data/NbnhhshQuery.scala @@ -0,0 +1,37 @@ +package cc.sukazyo.cono.morny.data + +import cc.sukazyo.cono.morny.util.OkHttpPublic.MediaTypes +import com.google.gson.Gson +import okhttp3.{OkHttpClient, Request, RequestBody, ResponseBody} + +import java.io.IOException +import scala.util.Using + +object NbnhhshQuery { + + case class Word (name: String, trans: Array[String], inputting: Array[String]) + case class GuessResult (words: Array[Word]) + + private case class GuessRequest (text: String) + + private val API_URL = "https://lab.magiconch.com/api/nbnhhsh/" + private val API_GUESS_METHOD = "guess/" + + private val httpClient = OkHttpClient() + + @throws[IOException] + def sendGuess (text: String): GuessResult = { + val requestJsonText = Gson().toJson(GuessRequest(text)) + val request = Request.Builder() + .url(API_URL + API_GUESS_METHOD) + .post(RequestBody.create(requestJsonText, MediaTypes.JSON)) + .build + Using (httpClient.newCall(request).execute) { response => + val body = response.body + if body eq null then throw IOException("Nbnhhsh Request: body is null.") + val x = s"{ 'words': ${body.string} }" + Gson().fromJson(x, classOf[GuessResult]) + }.get + } + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/data/ip186/IP186QueryHandler.scala b/src/main/scala/cc/sukazyo/cono/morny/data/ip186/IP186QueryHandler.scala index 65abaca..f9dc533 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/data/ip186/IP186QueryHandler.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/data/ip186/IP186QueryHandler.scala @@ -30,12 +30,11 @@ object IP186QueryHandler { @throws[IOException] private def commonQuery (requestUrl: String, queryParam: String): IP186Response = { val request = Request.Builder().url(requestUrl + "?" + queryParam).build - var _body_string: String|Null = null Using ((httpClient newCall request) execute) { response => - if response.body ne null then _body_string = response.body.string - } - if _body_string eq null then throw IOException("Response of ip186: body is empty!") - IP186Response(requestUrl, _body_string) + val _body = response.body + if _body eq null then throw IOException("Response of ip186: body is empty!") + IP186Response(requestUrl, _body.string) + }.get } }