From aafdcc1fb213017c94559d7bf8293bf6811f67a9 Mon Sep 17 00:00:00 2001 From: Eyre_S Date: Tue, 5 Sep 2023 14:14:01 +0800 Subject: [PATCH 1/5] scala port stage1 (not tested) --- .dockerignore | 2 + .gitignore | 2 + build.gradle | 56 ++-- gradle.properties | 4 +- .../cc/sukazyo/cono/morny/ServerMain.java | 296 ----------------- .../morny/bot/command/DirectMsgClear.java | 58 ---- .../cono/morny/bot/command/Encryptor.java | 208 ------------ .../cono/morny/bot/command/EventHack.java | 99 ------ .../morny/bot/command/GetUsernameAndId.java | 85 ----- .../cono/morny/bot/command/Ip186Query.java | 85 ----- .../morny/bot/command/MornyInfoOnHello.java | 44 --- .../morny/bot/command/MornyInformation.java | 301 ------------------ .../cono/morny/bot/command/Nbnhhsh.java | 80 ----- .../cono/morny/bot/command/Testing.java | 36 --- .../sukazyo/cono/morny/bot/command/喵呜.java | 82 ----- .../cono/morny/bot/command/私わね.java | 40 --- .../cono/morny/bot/event/OnCallMe.java | 181 ----------- .../cono/morny/bot/event/OnInlineQueries.java | 47 --- .../cono/morny/bot/event/OnUserRandoms.java | 42 --- .../morny/bot/event/OnUserSlashAction.java | 84 ----- .../cono/morny/bot/query/ITelegramQuery.java | 15 - .../cono/morny/bot/query/MornyQueries.java | 31 -- .../cono/morny/bot/query/MyInformation.java | 35 -- .../sukazyo/cono/morny/bot/query/RawText.java | 31 -- .../morny/bot/query/ShareToolBilibili.java | 80 ----- .../morny/bot/query/ShareToolTwitter.java | 50 --- .../morny/data/ip186/IP186QueryHandler.java | 89 ------ .../morny/data/ip186/IP186QueryResponse.java | 11 - .../cc/sukazyo/cono/morny/Log.java | 0 .../cc/sukazyo/cono/morny/MornyAbout.java | 0 .../cc/sukazyo/cono/morny/MornyAssets.java | 0 .../cc/sukazyo/cono/morny/MornyCoeur.java | 2 +- .../cc/sukazyo/cono/morny/MornyConfig.java | 0 .../cc/sukazyo/cono/morny/MornySystem.java | 0 .../cc/sukazyo/cono/morny/MornyTrusted.java | 0 .../cono/morny/bot/api/EventListener.java | 0 .../morny/bot/api/EventListenerManager.java | 0 .../cono/morny/bot/api/InlineQueryUnit.java | 0 .../sukazyo/cono/morny/bot/api/OnUpdate.java | 0 .../morny/bot/command/ISimpleCommand.java | 0 .../morny/bot/command/ITelegramCommand.java | 0 .../cono/morny/bot/command/MornyCommands.java | 32 +- .../sukazyo/cono/morny/bot/command/Roll.java | 0 .../cono/morny/bot/command/package-info.java | 0 .../cono/morny/bot/event/EventListeners.java | 13 +- .../morny/bot/event/OnActivityRecord.java | 0 .../cono/morny/bot/event/OnCallMsgSend.java | 0 .../morny/bot/event/OnEventHackHandle.java | 0 .../bot/event/OnKuohuanhuanNeedSleep.java | 0 .../bot/event/OnMedicationNotifyApply.java | 0 .../morny/bot/event/OnQuestionMarkReply.java | 0 .../morny/bot/event/OnRandomlyTriggered.java | 0 .../morny/bot/event/OnTelegramCommand.java | 0 .../morny/bot/event/OnUniMeowTrigger.java | 0 .../event/OnUpdateTimestampOffsetLock.java | 0 .../cono/morny/daemon/MedicationTimer.java | 0 .../cono/morny/daemon/MornyDaemons.java | 0 .../cono/morny/daemon/MornyReport.java | 2 +- .../cono/morny/daemon/TrackerDataManager.java | 0 .../cc/sukazyo/cono/morny/data/MornyJrrp.java | 0 .../sukazyo/cono/morny/data/NbnhhshQuery.java | 0 .../cono/morny/data/TelegramImages.java | 0 .../cono/morny/data/TelegramStickers.java | 0 .../cono/morny/internal/BuildConfigField.java | 0 .../cc/sukazyo/cono/morny/util/BiliTool.java | 0 .../cono/morny/util/CommonConvert.java | 0 .../cono/morny/util/CommonEncrypt.java | 0 .../sukazyo/cono/morny/util/CommonFormat.java | 0 .../sukazyo/cono/morny/util/CommonRandom.java | 0 .../cc/sukazyo/cono/morny/util/FileUtils.java | 0 .../sukazyo/cono/morny/util/OkHttpPublic.java | 0 .../cono/morny/util/UniversalCommand.java | 0 .../cono/morny/util/tgapi/ExtraAction.java | 0 .../cono/morny/util/tgapi/InputCommand.java | 0 .../cono/morny/util/tgapi/Standardize.java | 7 + .../tgapi/event/EventRuntimeException.java | 0 .../util/tgapi/formatting/MsgEscape.java | 0 .../util/tgapi/formatting/NamedUtils.java | 0 .../util/tgapi/formatting/TGToString.java | 0 .../tgapi/formatting/TGToStringFromChat.java | 1 + .../formatting/TGToStringFromMessage.java | 0 .../tgapi/formatting/TGToStringFromUser.java | 0 .../formatting/TelegramUserInformation.java | 0 .../cc/sukazyo/cono/morny/ServerMain.scala | 156 +++++++++ .../morny/bot/command/DirectMsgClear.scala | 54 ++++ .../cono/morny/bot/command/Encryptor.scala | 178 +++++++++++ .../cono/morny/bot/command/EventHack.scala | 56 ++++ .../morny/bot/command/GetUsernameAndId.scala | 66 ++++ .../cono/morny/bot/command/IP186Query.scala | 77 +++++ .../morny/bot/command/MornyInfoOnHello.scala | 35 ++ .../morny/bot/command/MornyInformation.scala | 167 ++++++++++ .../cono/morny/bot/command/Nbnhhsh.scala | 85 +++++ .../cono/morny/bot/command/Testing.scala | 30 ++ .../sukazyo/cono/morny/bot/command/喵呜.scala | 67 ++++ .../cono/morny/bot/command/私わね.scala | 26 ++ .../cono/morny/bot/event/OnCallMe.scala | 90 ++++++ .../cono/morny/bot/event/OnInlineQuery.scala | 37 +++ .../cono/morny/bot/event/OnUserRandom.scala | 38 +++ .../morny/bot/event/OnUserSlashAction.scala | 67 ++++ .../cono/morny/bot/query/ITelegramQuery.scala | 11 + .../cono/morny/bot/query/MornyQueries.scala | 27 ++ .../cono/morny/bot/query/MyInformation.scala | 31 ++ .../cono/morny/bot/query/RawText.scala | 27 ++ .../morny/bot/query/ShareToolBilibili.scala | 77 +++++ .../morny/bot/query/ShareToolTwitter.scala | 42 +++ .../morny/data/ip186/IP186QueryHandler.scala | 41 +++ .../cono/morny/data/ip186/IP186Response.scala | 3 + 107 files changed, 1556 insertions(+), 2163 deletions(-) delete mode 100644 src/main/java/cc/sukazyo/cono/morny/ServerMain.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/bot/command/DirectMsgClear.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/bot/command/Encryptor.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/bot/command/EventHack.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/bot/command/GetUsernameAndId.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/bot/command/Ip186Query.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/bot/command/MornyInfoOnHello.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/bot/command/MornyInformation.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/bot/command/Nbnhhsh.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/bot/command/Testing.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/bot/command/喵呜.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/bot/command/私わね.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/bot/event/OnCallMe.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/bot/event/OnInlineQueries.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/bot/event/OnUserRandoms.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/bot/event/OnUserSlashAction.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/bot/query/ITelegramQuery.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/bot/query/MornyQueries.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/bot/query/MyInformation.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/bot/query/RawText.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/bot/query/ShareToolBilibili.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/bot/query/ShareToolTwitter.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/data/ip186/IP186QueryHandler.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/data/ip186/IP186QueryResponse.java rename src/main/{java => old}/cc/sukazyo/cono/morny/Log.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/MornyAbout.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/MornyAssets.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/MornyCoeur.java (99%) rename src/main/{java => old}/cc/sukazyo/cono/morny/MornyConfig.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/MornySystem.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/MornyTrusted.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/bot/api/EventListener.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/bot/api/EventListenerManager.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/bot/api/InlineQueryUnit.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/bot/api/OnUpdate.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/bot/command/ISimpleCommand.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/bot/command/ITelegramCommand.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/bot/command/MornyCommands.java (96%) rename src/main/{java => old}/cc/sukazyo/cono/morny/bot/command/Roll.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/bot/command/package-info.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/bot/event/EventListeners.java (79%) rename src/main/{java => old}/cc/sukazyo/cono/morny/bot/event/OnActivityRecord.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/bot/event/OnCallMsgSend.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/bot/event/OnEventHackHandle.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/bot/event/OnKuohuanhuanNeedSleep.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/bot/event/OnMedicationNotifyApply.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/bot/event/OnQuestionMarkReply.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/bot/event/OnRandomlyTriggered.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/bot/event/OnTelegramCommand.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/bot/event/OnUniMeowTrigger.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/bot/event/OnUpdateTimestampOffsetLock.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/daemon/MedicationTimer.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/daemon/MornyDaemons.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/daemon/MornyReport.java (99%) rename src/main/{java => old}/cc/sukazyo/cono/morny/daemon/TrackerDataManager.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/data/MornyJrrp.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/data/NbnhhshQuery.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/data/TelegramImages.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/data/TelegramStickers.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/internal/BuildConfigField.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/util/BiliTool.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/util/CommonConvert.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/util/CommonEncrypt.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/util/CommonFormat.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/util/CommonRandom.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/util/FileUtils.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/util/OkHttpPublic.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/util/UniversalCommand.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/util/tgapi/ExtraAction.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/util/tgapi/InputCommand.java (100%) create mode 100644 src/main/old/cc/sukazyo/cono/morny/util/tgapi/Standardize.java rename src/main/{java => old}/cc/sukazyo/cono/morny/util/tgapi/event/EventRuntimeException.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/util/tgapi/formatting/MsgEscape.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/util/tgapi/formatting/NamedUtils.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToString.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromChat.java (92%) rename src/main/{java => old}/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromMessage.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromUser.java (100%) rename src/main/{java => old}/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramUserInformation.java (100%) create mode 100644 src/main/scala/cc/sukazyo/cono/morny/ServerMain.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/command/DirectMsgClear.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/command/Encryptor.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/command/EventHack.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/command/GetUsernameAndId.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/command/IP186Query.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyInfoOnHello.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyInformation.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/command/Nbnhhsh.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/command/Testing.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/command/喵呜.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/command/私わね.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/event/OnCallMe.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/event/OnInlineQuery.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/event/OnUserRandom.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/event/OnUserSlashAction.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/query/ITelegramQuery.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/query/MornyQueries.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/query/MyInformation.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/query/RawText.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/query/ShareToolBilibili.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/bot/query/ShareToolTwitter.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/data/ip186/IP186QueryHandler.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/data/ip186/IP186Response.scala diff --git a/.dockerignore b/.dockerignore index df3d0f1..e23a3f5 100644 --- a/.dockerignore +++ b/.dockerignore @@ -10,6 +10,8 @@ #build /build/ /bin/ +.metals/ +.bloop/ .project lcoal.properties diff --git a/.gitignore b/.gitignore index df3d0f1..e23a3f5 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,8 @@ #build /build/ /bin/ +.metals/ +.bloop/ .project lcoal.properties diff --git a/build.gradle b/build.gradle index aff5df9..a15ac59 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'java' + id 'scala' id 'java-library' id 'application' id 'maven-publish' @@ -50,7 +50,9 @@ final long proj_code_time = proj_clean ? grgit.head().dateTime.toInstant().toEpo final JavaVersion proj_java = JavaVersion.VERSION_17 final Charset proj_file_encoding = StandardCharsets.UTF_8 - +final proj_scala_api = 3 +//final proj_scala_lib = proj_scala_api+'.4.0-RC1-bin-20230901-89e8dba-NIGHTLY' +final proj_scala_lib = proj_scala_api+'.3.1-RC7' String publish_local_url = null String publish_remote_url = null String publish_remote_username = null @@ -72,6 +74,7 @@ repositories { dependencies { + api "org.scala-lang:scala3-library_3:${proj_scala_lib}" compileOnlyApi "com.github.spotbugs:spotbugs-annotations:${lib_spotbugs_v}" implementation "cc.sukazyo:messiva:${lib_messiva_v}" @@ -86,8 +89,30 @@ dependencies { } -application { - mainClass = proj_application_main +sourceSets { + main { + scala { srcDirs = ['src/main/scala', 'src/main/old'] } + } +} + +scala { + + compileJava { + + sourceCompatibility '17' + targetCompatibility '17' + + options.encoding = proj_file_encoding.name() + + } + + compileScala { + + options.encoding = proj_file_encoding.name() + scalaCompileOptions.encoding = proj_file_encoding.name() + + } + } test { @@ -97,27 +122,8 @@ test { } } -java { - - sourceCompatibility proj_java - targetCompatibility proj_java - - withSourcesJar() - -} - -tasks.withType(JavaCompile).configureEach { - options.encoding = proj_file_encoding.name() -} - -tasks.withType(Javadoc).configureEach { - options.encoding = proj_file_encoding.name() - options.docEncoding = proj_file_encoding.name() - options.charSet = proj_file_encoding.name() -} - -tasks.test { - useJUnitPlatform() +application { + mainClass = proj_application_main } buildConfig { diff --git a/gradle.properties b/gradle.properties index 2996049..908c69b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,8 +7,8 @@ MORNY_COMMIT_PATH = https://github.com/Eyre-S/Coeur-Morny-Cono/commit/%s VERSION = 1.0.0-RC4 -USE_DELTA = false -VERSION_DELTA = +USE_DELTA = true +VERSION_DELTA = scalaport1 CODENAME = beiping diff --git a/src/main/java/cc/sukazyo/cono/morny/ServerMain.java b/src/main/java/cc/sukazyo/cono/morny/ServerMain.java deleted file mode 100644 index 208ed1b..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/ServerMain.java +++ /dev/null @@ -1,296 +0,0 @@ -package cc.sukazyo.cono.morny; - -import cc.sukazyo.cono.morny.util.CommonFormat; - -import javax.annotation.Nonnull; - -import java.time.ZoneOffset; -import java.util.ArrayList; -import java.util.List; - -import static cc.sukazyo.cono.morny.Log.logger; - -/** - * 程序启动入口
- *
- * 会处理程序传入的参数和选项等数据,并执行对应的启动方式
- * - * @since 0.4.0.0 - */ -public class ServerMain { - - public static final long systemStartupTime = System.currentTimeMillis(); - - private static final String THREAD_MORNY_INIT = "morny-init"; - - /** - * 程序入口,也是参数处理器
- *
- * 以 {@code -} 开头的参数会被解析为选项
- *
- * 支持以下选项 - * - * 除去选项之外,第一个参数会被赋值为 bot 的 telegram bot api token, - * 第二个参数会被赋值为 bot 的 username 限定名。其余的参数会被认定为无法理解。
- * 自 {@code 0.4.2.3},token 和 username 的赋值已被选项组支持
- * 自 {@code 0.5.0.4},旧的直接通过参数为 bot token & username 赋值的方式已被删除 - * 使用参数所进行取值的 token 和 username 已被转移至 {@code --token} 和 {@code --username} 参数
- * - * @see MornyCoeur#init - * @since 0.4.0.0 - * @param args 参数组 - */ - public static void main (@Nonnull String[] args) { - - //# - //# 启动参数设置区块 - //# - final MornyConfig.Prototype config = new MornyConfig.Prototype(); - boolean versionEchoMode = false; - boolean welcomeEchoMode = false; - boolean showWelcome = true; - - config.eventOutdatedTimestamp = systemStartupTime; - - List unknownArgs = new ArrayList<>(); - - //# 从命令行参数设置启动参数 - for (int i = 0; i < args.length; i++) { - - if (args[i].startsWith("-")) { - - switch (args[i]) { - case "-d", "--dbg", "--debug" -> { - Log.debug(true); - continue; - } - case "--outdated-block", "-ob" -> { - config.eventIgnoreOutdated = true; - continue; - } - case "--no-hello", "-hf", "--quiet", "-q" -> { - showWelcome = false; - continue; - } - case "--only-hello", "-ho", "-o", "-hi" -> { - welcomeEchoMode = true; - continue; - } - case "--version", "-v" -> { - versionEchoMode = true; - continue; - } - case "--token", "-t" -> { - i++; - config.telegramBotKey = args[i]; - continue; - } - case "--username", "-u" -> { - i++; - config.telegramBotUsername = args[i]; - continue; - } - case "--master", "-mm" -> { - i++; - config.trustedMaster = Long.parseLong(args[i]); - continue; - } - case "--trusted-chat", "-trs" -> { - i++; - config.trustedChat = Long.parseLong(args[i]); - continue; - } - // noinspection SpellCheckingInspection - case "--trusted-reader-dinner", "-trsd" -> { - i++; - config.dinnerTrustedReaders.add(Long.parseLong(args[i])); - continue; - } - case "--dinner-chat", "-chd" -> { - i++; - config.dinnerChatId = Long.parseLong(args[i]); - continue; - } - case "--auto-cmd", "-cmd", "-c" -> { - config.commandLoginRefresh = true; - config.commandLogoutClear = true; - continue; - } - case "--auto-cmd-list", "-ca" -> { - config.commandLoginRefresh = true; - continue; - } - case "--auto-cmd-remove", "-cr" -> { - config.commandLogoutClear = true; - continue; - } - case "--api", "-a" -> { - i++; - config.telegramBotApiServer = args[i]; - continue; - } - case "--api-files", "files-api", "-af" -> { - i++; - config.telegramBotApiServer4File = args[i]; - continue; - } - case "--report-to" -> { - i++; - config.reportToChat = Long.parseLong(args[i]); - continue; - } - case "--medication-notify-chat", "-medc" -> { - i++; - config.medicationNotifyToChat = Long.parseLong(args[i]); - continue; - } - case "--medication-notify-timezone", "-medtz" -> { - i++; - config.medicationTimerUseTimezone = ZoneOffset.ofHours(Integer.parseInt(args[i])); - continue; - } - case "--medication-notify-times", "-medt" -> { - i++; - for (String u : args[i].split(",")) - config.medicationNotifyAt.add(Integer.parseInt(u)); - continue; - } - } - - } - - unknownArgs.add(args[i]); - - } - - //# 从环境变量设置启动参数 - String propToken = null; - String propTokenKey = null; - for (String iKey : MornyConfig.PROP_TOKEN_KEY) { - if (System.getenv(iKey) != null) { - propToken = System.getenv(iKey); - propTokenKey = iKey; - } - } - - - //# - //# 启动信息输出 - //# 启动相关参数的检查和处理 - //# - - if (showWelcome) logger.info(MornyAbout.MORNY_PREVIEW_IMAGE_ASCII); - if (welcomeEchoMode) return; - - unknownArgs.forEach(arg -> logger.warn("Can't understand arg to some meaning :\n " + arg)); - - if (Log.debug()) - logger.warn("Debug log output enabled.\n It may lower your performance, make sure that you are not in production environment."); - - logger.debug("Debug log output enabled."); - - if (versionEchoMode) { - - logger.info(String.format(""" - Morny Cono Version - - version : - Morny %s - %s%s - - md5hash : - %s - - gitstat : - %s - - co.time : - %d - %s [UTC]""", - MornySystem.CODENAME.toUpperCase(), - MornySystem.VERSION_BASE, - MornySystem.isUseDelta() ? "-δ"+MornySystem.VERSION_DELTA : "", - MornySystem.getJarMd5(), - MornySystem.isGitBuild() ? (String.format( - "on commit %s\n %s", - MornySystem.isCleanBuild() ? "- clean-build" : "<δ/non-clean-build>", - BuildConfig.COMMIT - )) : "", - BuildConfig.CODE_TIMESTAMP, - CommonFormat.formatDate(BuildConfig.CODE_TIMESTAMP, 0) - )); - return; - - } - - logger.info(String.format(""" - ServerMain.java Loaded >>> - - version %s - - Morny %s - - <%s> [%d]""", - MornySystem.VERSION_FULL, - MornySystem.CODENAME.toUpperCase(), - MornySystem.getJarMd5(), BuildConfig.CODE_TIMESTAMP - )); - - //# - //# Coeur 参数检查和正式启动主程序 - //# - - if (propToken != null) { - config.telegramBotKey = propToken; - logger.info("Parameter set by EnvVar $"+propTokenKey); - } - - Thread.currentThread().setName(THREAD_MORNY_INIT); - try { - MornyCoeur.init(new MornyConfig(config)); - } catch (MornyConfig.CheckFailure.NullTelegramBotKey ignore) { - logger.info("Parameter required has no value:\n --token."); - } catch (MornyConfig.CheckFailure e) { - logger.error("Unknown failure occurred while starting ServerMain!:"); - e.printStackTrace(System.out); - } - - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/command/DirectMsgClear.java b/src/main/java/cc/sukazyo/cono/morny/bot/command/DirectMsgClear.java deleted file mode 100644 index 54b850a..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/bot/command/DirectMsgClear.java +++ /dev/null @@ -1,58 +0,0 @@ -package cc.sukazyo.cono.morny.bot.command; - -import cc.sukazyo.cono.morny.MornyCoeur; -import cc.sukazyo.cono.morny.util.tgapi.InputCommand; -import com.pengrad.telegrambot.model.Chat; -import com.pengrad.telegrambot.model.Update; -import com.pengrad.telegrambot.request.DeleteMessage; -import com.pengrad.telegrambot.request.GetChatMember; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import static cc.sukazyo.cono.morny.Log.logger; - -public class DirectMsgClear implements ISimpleCommand { - - @Nonnull @Override public String getName () { return "r"; } - - @Nullable @Override public String[] getAliases () { return new String[0]; } - - @Override - public void execute (@Nonnull InputCommand command, @Nonnull Update event) { - - logger.debug("Executing command /r"); - if (event.message().replyToMessage() == null) return; - logger.trace("Message is a reply"); - if (event.message().replyToMessage().from().id() != MornyCoeur.getUserid()) return; - logger.trace("Message is from me"); - if (System.currentTimeMillis()/1000 - event.message().replyToMessage().date() > 48*60*60) return; - logger.trace("Message is not older than 48 hours"); - - final boolean isTrusted = MornyCoeur.trustedInstance().isTrusted(event.message().from().id()); - - if ( - isTrusted || ( - event.message().replyToMessage().replyToMessage() != null && - event.message().replyToMessage().replyToMessage().from().id().equals(event.message().from().id()) - ) - ) { - - MornyCoeur.extra().exec(new DeleteMessage( - event.message().chat().id(), event.message().replyToMessage().messageId() - )); - if (event.message().chat().type() == Chat.Type.Private || ( - MornyCoeur.extra().exec( - new GetChatMember(event.message().chat().id(), event.message().from().id()) - ).chatMember().canDeleteMessages() - )) { - MornyCoeur.extra().exec(new DeleteMessage( - event.message().chat().id(), event.message().messageId() - )); - } - - } else logger.trace("User is not trusted"); - - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/command/Encryptor.java b/src/main/java/cc/sukazyo/cono/morny/bot/command/Encryptor.java deleted file mode 100644 index 5ceb213..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/bot/command/Encryptor.java +++ /dev/null @@ -1,208 +0,0 @@ -package cc.sukazyo.cono.morny.bot.command; - -import cc.sukazyo.cono.morny.MornyCoeur; -import cc.sukazyo.cono.morny.daemon.MornyReport; -import cc.sukazyo.cono.morny.data.TelegramStickers; -import cc.sukazyo.cono.morny.util.CommonConvert; -import cc.sukazyo.cono.morny.util.CommonEncrypt; -import cc.sukazyo.cono.morny.util.tgapi.InputCommand; -import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape; -import com.pengrad.telegrambot.model.PhotoSize; -import com.pengrad.telegrambot.model.Update; -import com.pengrad.telegrambot.model.request.ParseMode; -import com.pengrad.telegrambot.request.GetFile; -import com.pengrad.telegrambot.request.SendDocument; -import com.pengrad.telegrambot.request.SendMessage; -import com.pengrad.telegrambot.request.SendSticker; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.io.IOException; -import java.util.Base64; - -import static cc.sukazyo.cono.morny.Log.logger; - -public class Encryptor implements ITelegramCommand { - - @Nonnull @Override public String getName () { return "encrypt"; } - @Nullable @Override public String[] getAliases () { return new String[0]; } - @Nonnull @Override public String getParamRule () { return "[algorithm|(l)] [(uppercase)]"; } - @Nonnull @Override public String getDescription () { return "通过指定算法加密回复的内容 (目前只支持文本)"; } - - @Override - public void execute (@Nonnull InputCommand command, @Nonnull Update event) { - - // show a simple help page - // the first paragraph lists available encrypt algorithms, and its aliases. - // with the separator "---", - // the second paragraphs shows the mods available and its aliases. - if (!command.hasArgs() || (command.getArgs()[0].equals("l") && command.getArgs().length==1)) { - MornyCoeur.extra().exec(new SendMessage( - event.message().chat().id(), """ - base64, b64 - base64url, base64u, b64u - base64decode, base64d, b64d - base64url-decode, base64ud, b64ud - sha1 - sha256 - sha512 - md5 - --- - uppercase, upper, u (sha1/sha256/sha512/md5 only) - """ - ).replyToMessageId(event.message().messageId()).parseMode(ParseMode.HTML)); - return; - } - - // param1 is the encrypting algorithm, it MUST EXIST. - // so the mod will be set in param2. - // and for now only support UPPERCASE mod, so it exists in param2, or there should no any params. - boolean modUpperCase = false; - if (command.getArgs().length > 1) { - if (command.getArgs().length < 3 && ( - command.getArgs()[1].equalsIgnoreCase("uppercase") || - command.getArgs()[1].equalsIgnoreCase("u") || - command.getArgs()[1].equalsIgnoreCase("upper") - )) { - modUpperCase = true; - } else { - MornyCoeur.extra().exec(new SendSticker( - event.message().chat().id(), TelegramStickers.ID_404 - ).replyToMessageId(event.message().messageId())); - return; - } - } - - // for now, only support reply to A TEXT MESSAGE or ONE UNIVERSAL FILE - // if the replied message contains a UNIVERSAL FILE, it will use the file and will not use the text with it - // do not support TELEGRAM INLINE IMAGE/VIDEO/AUDIO yet - // do not support MULTI_FILE yet - // if there's no text message in reply, it will report null as result. - boolean inputText; - byte[] data; - String dataName; - if (event.message().replyToMessage() != null && event.message().replyToMessage().document() != null) { - inputText = false; - try { - data = MornyCoeur.getAccount().getFileContent(MornyCoeur.extra().exec(new GetFile( - event.message().replyToMessage().document().fileId() - )).file()); - } catch (IOException e) { - logger.warn("NetworkRequest error: TelegramFileAPI:\n\t" + e.getMessage()); - MornyReport.exception(e, "NetworkRequest error: TelegramFileAPI"); - MornyCoeur.extra().exec(new SendSticker( - event.message().chat().id(), - TelegramStickers.ID_NETWORK_ERR - ).replyToMessageId(event.message().messageId())); - return; - } - dataName = event.message().replyToMessage().document().fileName(); - } else if (event.message().replyToMessage() != null && event.message().replyToMessage().photo() != null) { - inputText = false; - try { - PhotoSize originPhoto = null; - long photoSize = 0; - for (PhotoSize size : event.message().replyToMessage().photo()) if (photoSize < (long)size.width() *size.height()) { - originPhoto = size; - photoSize = (long)size.width() *size.height(); - } // found max size (original) image in available sizes - if (originPhoto==null) throw new IOException("no photo object from api."); - data = MornyCoeur.getAccount().getFileContent(MornyCoeur.extra().exec(new GetFile( - originPhoto.fileId() - )).file()); - } catch (IOException e) { - logger.warn("NetworkRequest error: TelegramFileAPI:\n\t" + e.getMessage()); - MornyReport.exception(e, "NetworkRequest error: TelegramFileAPI"); - MornyCoeur.extra().exec(new SendSticker( - event.message().chat().id(), - TelegramStickers.ID_NETWORK_ERR - ).replyToMessageId(event.message().messageId())); - return; - } - dataName = "photo"+CommonConvert.byteArrayToHex(CommonEncrypt.hashMd5(String.valueOf(System.currentTimeMillis()))).substring(32-12).toUpperCase()+".png"; - } else if (event.message().replyToMessage() != null && event.message().replyToMessage().text() != null) { - inputText = true; - data = event.message().replyToMessage().text().getBytes(CommonEncrypt.ENCRYPT_STANDARD_CHARSET); - dataName = null; - } else { - MornyCoeur.extra().exec(new SendMessage( - event.message().chat().id(), - "null" - ).replyToMessageId(event.message().messageId()).parseMode(ParseMode.HTML)); - return; - } - - boolean echoString = true; - String resultString = null; - byte[] result = null; - String resultName = null; - switch (command.getArgs()[0]) { - case "base64", "b64", "base64url", "base64u", "b64u" -> { - final Base64.Encoder b64tool = command.getArgs()[0].contains("u") ? Base64.getUrlEncoder() : Base64.getEncoder(); - result = b64tool.encode(data); - if (!inputText) { - echoString = false; - resultName = dataName+".b64.txt"; - } else { - resultString = new String(result, CommonEncrypt.ENCRYPT_STANDARD_CHARSET); - } - } - case "base64decode", "base64d", "b64d", "base64url-decode", "base64ud", "b64ud" -> { - final Base64.Decoder b64tool = command.getArgs()[0].contains("u") ? Base64.getUrlDecoder() : Base64.getDecoder(); - try { result = b64tool.decode(data); } - catch (IllegalArgumentException e) { - MornyCoeur.extra().exec(new SendSticker( - event.message().chat().id(), TelegramStickers.ID_404 - ).replyToMessageId(event.message().messageId())); - return; - } - if (!inputText) { - echoString = false; - resultName = CommonEncrypt.base64FilenameLint(dataName); - } else { - resultString = new String(result, CommonEncrypt.ENCRYPT_STANDARD_CHARSET); - } - } - case "md5" -> resultString = CommonConvert.byteArrayToHex(CommonEncrypt.hashMd5(data)); - case "sha1" -> resultString = CommonConvert.byteArrayToHex(CommonEncrypt.hashSha1(data)); - case "sha256" -> resultString = CommonConvert.byteArrayToHex(CommonEncrypt.hashSha256(data)); - case "sha512" -> resultString = CommonConvert.byteArrayToHex(CommonEncrypt.hashSha512(data)); - default -> { - MornyCoeur.extra().exec(new SendSticker( - event.message().chat().id(), TelegramStickers.ID_404 - ).replyToMessageId(event.message().messageId())); - return; - } - } - if (modUpperCase) { - // modUpperCase support only algorithm that showed as HEX value. - // it means md5, sha1, sha256, sha512 here. - // other will report wrong param. - switch (command.getArgs()[0]) { - case "md5", "sha1", "sha256", "sha512" -> { - assert resultString != null; - resultString = resultString.toUpperCase(); - } - default -> { - MornyCoeur.extra().exec(new SendSticker( - event.message().chat().id(), TelegramStickers.ID_404 - ).replyToMessageId(event.message().messageId())); - return; - } - } - } - if (echoString) { - MornyCoeur.extra().exec(new SendMessage( - event.message().chat().id(), - "
" + MsgEscape.escapeHtml(resultString) + "
" - ).replyToMessageId(event.message().messageId()).parseMode(ParseMode.HTML)); - } else { - MornyCoeur.extra().exec(new SendDocument( - event.message().chat().id(), - result - ).fileName(resultName).replyToMessageId(event.message().messageId())); - } - - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/command/EventHack.java b/src/main/java/cc/sukazyo/cono/morny/bot/command/EventHack.java deleted file mode 100644 index dbcfc81..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/bot/command/EventHack.java +++ /dev/null @@ -1,99 +0,0 @@ -package cc.sukazyo.cono.morny.bot.command; - -import cc.sukazyo.cono.morny.MornyCoeur; -import cc.sukazyo.cono.morny.MornyTrusted; -import cc.sukazyo.cono.morny.bot.event.OnEventHackHandle; -import cc.sukazyo.cono.morny.data.TelegramStickers; - -import cc.sukazyo.cono.morny.util.tgapi.InputCommand; -import com.pengrad.telegrambot.model.Update; -import com.pengrad.telegrambot.request.SendSticker; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -/** - * {@link OnEventHackHandle} 的命令行前端 - * @since 0.4.2.0 - */ -public class EventHack implements ITelegramCommand { - - @Nonnull @Override public String getName () { return "event_hack"; } - @Nullable @Override public String[] getAliases () { return null; } - @Nonnull @Override public String getParamRule () { return "[(user|group|any)]"; } - @Nonnull @Override public String getDescription () { return "输出 bot 下一个获取到的事件序列化数据"; } - - /** - * {@link OnEventHackHandle} 的命令行前端
- *
- * 实现了通过命令行进行 EventHack 功能。
- * 支持三种模式,默认为 {@link OnEventHackHandle.HackType#USER USER}, - * {@link OnEventHackHandle.HackType#ANY ANY} 时,将会通过 {@link MornyTrusted#isTrusted(long)} 检查触发用户的权限 - * - * @param event 命令基础参数,触发的事件对象本身 - * @param command 命令基础参数,解析出的命令对象 - * @since 0.4.2.0 - */ - @Override - public void execute (@Nonnull InputCommand command, @Nonnull Update event) { - - enum Status { - OK, - FORBIDDEN_FOR_ANY - } - Status status; - - String x_mode = ""; - if (command.hasArgs()) { - x_mode = command.getArgs()[0]; - } - switch (x_mode) { - case "any" -> { - if (MornyCoeur.trustedInstance().isTrusted(event.message().from().id())) { - OnEventHackHandle.registerHack( - event.message().messageId(), - event.message().from().id(), - event.message().chat().id(), - OnEventHackHandle.HackType.ANY - ); - status = Status.OK; - } else { - status = Status.FORBIDDEN_FOR_ANY; - } - } - case "group" -> { - OnEventHackHandle.registerHack( - event.message().messageId(), - event.message().from().id(), - event.message().chat().id(), - OnEventHackHandle.HackType.GROUP - ); - status = Status.OK; - } - default -> { - OnEventHackHandle.registerHack( - event.message().messageId(), - event.message().from().id(), - event.message().chat().id(), - OnEventHackHandle.HackType.USER - ); - status = Status.OK; - } - } - - switch (status) { - case OK -> MornyCoeur.extra().exec(new SendSticker( - event.message().chat().id(), - TelegramStickers.ID_WAITING - ).replyToMessageId(event.message().messageId()) - ); - case FORBIDDEN_FOR_ANY -> MornyCoeur.extra().exec(new SendSticker( - event.message().chat().id(), - TelegramStickers.ID_403 - ).replyToMessageId(event.message().messageId()) - ); - } - - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/command/GetUsernameAndId.java b/src/main/java/cc/sukazyo/cono/morny/bot/command/GetUsernameAndId.java deleted file mode 100644 index 553b14f..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/bot/command/GetUsernameAndId.java +++ /dev/null @@ -1,85 +0,0 @@ -package cc.sukazyo.cono.morny.bot.command; - -import cc.sukazyo.cono.morny.MornyCoeur; -import cc.sukazyo.cono.morny.util.tgapi.InputCommand; -import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramUserInformation; -import com.pengrad.telegrambot.model.Update; -import com.pengrad.telegrambot.model.User; -import com.pengrad.telegrambot.model.request.ParseMode; -import com.pengrad.telegrambot.request.GetChatMember; -import com.pengrad.telegrambot.request.SendMessage; -import com.pengrad.telegrambot.response.GetChatMemberResponse; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -public class GetUsernameAndId implements ITelegramCommand { - - @Nonnull @Override public String getName () { return "user"; } - @Nullable @Override public String[] getAliases () { return null; } - @Nonnull @Override public String getParamRule () { return "[userid]"; } - @Nonnull @Override public String getDescription () { return "获取指定或回复的用户相关信息"; } - - @Override - public void execute (@Nonnull InputCommand command, @Nonnull Update event) { - - final String[] args = command.getArgs(); - - // 不支持大于一个参数 - if (args.length > 1) { MornyCoeur.extra().exec(new SendMessage( - event.message().chat().id(), - "[Unavailable] Too much arguments." - ).replyToMessageId(event.message().messageId())); return; } - - // 发送者自己的 id - long userId = event.message().from().id(); - - // 如果有回复某个人,则使用被回复人的 id - if (event.message().replyToMessage()!= null) { - userId = event.message().replyToMessage().from().id(); - } - // 如果有指定 id,则使用指定的 id - if (args.length > 0) { - try { - userId = Long.parseLong(args[0]); - } catch (NumberFormatException e) { - MornyCoeur.extra().exec(new SendMessage( - event.message().chat().id(), - "[Unavailable] " + e.getMessage() - ).replyToMessageId(event.message().messageId())); - return; - } - } - - // 重新获取用户对象 - final GetChatMemberResponse response = MornyCoeur.getAccount().execute( - new GetChatMember(event.message().chat().id(), userId) - ); - - if (response.chatMember() == null) { - MornyCoeur.extra().exec(new SendMessage( - event.message().chat().id(), - "[Unavailable] user not found." - ).replyToMessageId(event.message().messageId())); - return; - } - - // 获取并发送用户信息 - final User user = response.chatMember().user(); - - if (user.id() == 136817688) { - MornyCoeur.extra().exec(new SendMessage( - event.message().chat().id(), - "$__channel_identify" - )); - return; - } - - MornyCoeur.extra().exec(new SendMessage( - event.message().chat().id(), - TelegramUserInformation.informationOutputHTML(user) - ).replyToMessageId(event.message().messageId()).parseMode(ParseMode.HTML)); - - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/command/Ip186Query.java b/src/main/java/cc/sukazyo/cono/morny/bot/command/Ip186Query.java deleted file mode 100644 index 4d5b4f3..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/bot/command/Ip186Query.java +++ /dev/null @@ -1,85 +0,0 @@ -package cc.sukazyo.cono.morny.bot.command; - -import cc.sukazyo.cono.morny.MornyCoeur; -import cc.sukazyo.cono.morny.data.ip186.IP186QueryResponse; -import cc.sukazyo.cono.morny.data.ip186.IP186QueryHandler; -import cc.sukazyo.cono.morny.util.tgapi.InputCommand; -import com.pengrad.telegrambot.model.Update; -import com.pengrad.telegrambot.model.request.ParseMode; -import com.pengrad.telegrambot.request.SendMessage; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import static cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml; - - -/** - * {@value IP186QueryHandler#SITE_URL} 查询的 telegram 命令前端 - * @since 0.4.2.10 - */ -public class Ip186Query { - - public static final String CMD_IP = "ip"; - public static final String CMD_WHOIS = "whois"; - - public static class Ip implements ITelegramCommand { - @Nonnull @Override public String getName () { return CMD_IP; } - @Nullable @Override public String[] getAliases () { return new String[0]; } - @Nonnull @Override public String getParamRule () { return "[ip]"; } - @Nonnull @Override public String getDescription () { return "通过 https://ip.186526.xyz 查询 ip 资料"; } - @Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { exec(event, command); } - } - - public static class Whois implements ITelegramCommand { - @Nonnull @Override public String getName () { return CMD_WHOIS; } - @Nullable @Override public String[] getAliases () { return new String[0]; } - @Nonnull @Override public String getParamRule () { return "[domain]"; } - @Nonnull @Override public String getDescription () { return "通过 https://ip.186526.xyz 查询域名资料"; } - @Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { exec(event, command); } - } - - private static void exec (@Nonnull Update event, @Nonnull InputCommand command) { - - String arg = null; - if (!command.hasArgs()) { - if (event.message().replyToMessage() != null) { - arg = event.message().replyToMessage().text(); - } - } else if (command.getArgs().length > 1) { - MornyCoeur.extra().exec(new SendMessage( - event.message().chat().id(), - "[Unavailable] Too much arguments." - ).replyToMessageId(event.message().messageId())); - return; - } else { - arg = command.getArgs()[0]; - } - if (arg == null) { - MornyCoeur.extra().exec(new SendMessage( - event.message().chat().id(), - "[Unavailable] No ip defined." - ).replyToMessageId(event.message().messageId())); - return; - } - - try { - IP186QueryResponse response = switch (command.getCommand()) { - case CMD_IP -> IP186QueryHandler.queryIp(arg); - case CMD_WHOIS -> IP186QueryHandler.queryWhoisPretty(arg); - default -> throw new IllegalArgumentException("Unknown 186-IP query method " + command.getCommand()); - }; - MornyCoeur.extra().exec(new SendMessage( - event.message().chat().id(), - escapeHtml(response.url()) + "\n" + escapeHtml(response.body()) + "" - ).parseMode(ParseMode.HTML).replyToMessageId(event.message().messageId())); - } catch (Exception e) { - MornyCoeur.extra().exec(new SendMessage( - event.message().chat().id(), - "[Exception] in query:\n" + escapeHtml(e.getMessage()) + "" - ).parseMode(ParseMode.HTML).replyToMessageId(event.message().messageId())); - } - - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyInfoOnHello.java b/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyInfoOnHello.java deleted file mode 100644 index 245bae8..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyInfoOnHello.java +++ /dev/null @@ -1,44 +0,0 @@ -package cc.sukazyo.cono.morny.bot.command; - -import com.pengrad.telegrambot.model.Update; -import com.pengrad.telegrambot.model.request.ParseMode; -import com.pengrad.telegrambot.request.SendPhoto; - -import cc.sukazyo.cono.morny.MornyCoeur; -import cc.sukazyo.cono.morny.util.tgapi.InputCommand; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -/** - * The implementation of Telegram special command `/start`. - * - * @see MornyInformation related class where some data comes from. - * - * @since 1.0.0-RC4 - */ -public class MornyInfoOnHello implements ISimpleCommand { - - @Nonnull @Override public String getName() { return "start"; } - @Nullable @Override public String[] getAliases() { return new String[0]; } - // @Override public String getParamRule() { return ""; } - // @Override public String getDescription() { return "" } - - @Override - public void execute(@Nonnull InputCommand command, @Nonnull Update event) { - MornyCoeur.extra().exec(new SendPhoto( - event.message().chat().id(), - MornyInformation.getAboutPic() - ).caption(""" - 欢迎使用 Morny Cono来自安妮的侍从小鼠。 - Morny 具有各种各样的功能。 - - ———————————————— - %s - ———————————————— - - (你可以随时通过 /info 重新获得这些信息)""".formatted(MornyInformation.getMornyAboutLinksHTML()) - ).parseMode(ParseMode.HTML)); - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyInformation.java b/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyInformation.java deleted file mode 100644 index 6a204e0..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyInformation.java +++ /dev/null @@ -1,301 +0,0 @@ -package cc.sukazyo.cono.morny.bot.command; - -import cc.sukazyo.cono.morny.BuildConfig; -import cc.sukazyo.cono.morny.MornyAbout; -import cc.sukazyo.cono.morny.MornyCoeur; -import cc.sukazyo.cono.morny.MornySystem; -import cc.sukazyo.cono.morny.data.TelegramImages; -import cc.sukazyo.cono.morny.data.TelegramStickers; -import cc.sukazyo.cono.morny.util.tgapi.ExtraAction; -import cc.sukazyo.cono.morny.util.tgapi.InputCommand; - -import com.pengrad.telegrambot.model.Update; -import com.pengrad.telegrambot.model.request.ParseMode; -import com.pengrad.telegrambot.request.SendMessage; -import com.pengrad.telegrambot.request.SendPhoto; -import com.pengrad.telegrambot.request.SendSticker; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.Objects; - -import static cc.sukazyo.cono.morny.util.CommonFormat.formatDate; -import static cc.sukazyo.cono.morny.util.CommonFormat.formatDuration; -import static cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml; - -public class MornyInformation implements ITelegramCommand { - - private static final String SUB_STICKER = "stickers"; - private static final String SUB_RUNTIME = "runtime"; - private static final String SUB_VERSION = "version"; - private static final String SUB_VERSION_2 = "v"; - - @Nonnull @Override public String getName () { return "info"; } - @Nullable @Override public String[] getAliases () { return new String[0]; } - @Nonnull @Override public String getParamRule () { return "[(version|runtime|stickers[.IDs])]"; } - @Nonnull @Override public String getDescription () { return "输出当前 Morny 的各种信息"; } - - @Override - public void execute (@Nonnull InputCommand command, @Nonnull Update event) { - - if (!command.hasArgs()) { - echoInfo(event.message().chat().id(), event.message().messageId()); - return; - } - - final String action = command.getArgs()[0]; - - if (action.startsWith(SUB_STICKER)) { - echoStickers(command, event); - } else if (action.equals(SUB_RUNTIME)) { - echoRuntime(event); - } else if (action.equals(SUB_VERSION) || action.equals(SUB_VERSION_2)) { - echoVersion(event); - } else { - echo404(event); - } - - } - - /** - * Subcommand /info without params. - * - * @since 1.0.0-RC4 - */ - public void echoInfo (long chatId, int replayToMessage) { - MornyCoeur.extra().exec(new SendPhoto( - chatId, - getAboutPic() - ).caption(""" - Morny Cono - 来自安妮的侍从小鼠。 - ———————————————— - %s""".formatted(getMornyAboutLinksHTML()) - ).parseMode(ParseMode.HTML).replyToMessageId(replayToMessage)); - } - - /** - * subcommand /info stickers - * - * @see #SUB_STICKER - */ - public void echoStickers (@Nonnull InputCommand command, @Nonnull Update event) { - final long echoTo = event.message().chat().id(); - final int replyToMessage = event.message().messageId(); - String id = null; - if (command.getArgs()[0].equals(SUB_STICKER)) { - if (command.getArgs().length == 1) { - id = ""; - } else if (command.getArgs().length == 2) { - id = command.getArgs()[1]; - } - } else if (command.getArgs().length == 1) { - if (command.getArgs()[0].startsWith(SUB_STICKER+".") || command.getArgs()[0].startsWith(SUB_STICKER+"#")) { - id = command.getArgs()[0].substring(SUB_STICKER.length()+1); - } - } - if (id == null) { echo404(event); return; } - echoStickers(id, echoTo, replyToMessage); - } - - /** - * 向 telegram 输出一个或全部 sticker. - * - * @param id - * sticker 在 {@link TelegramStickers} 中的字段名。 - * 使用 {@link ""}(空字符串)(不是{@link null}) 表示输出全部 sticker - * @param chatId 目标 chat id - * @param messageId 要回复的消息 id,依据 {@link TelegramStickers#echoStickerByID(String, ExtraAction, long, int) 上游} - * 逻辑,使用 {@link -1} 表示不回复消息。 - * - * @see TelegramStickers#echoStickerByID(String, ExtraAction, long, int) - * @see TelegramStickers#echoAllStickers(ExtraAction, long, int) - */ - public static void echoStickers (@Nonnull String id, long chatId, int messageId) { - if (id.isEmpty()) TelegramStickers.echoAllStickers(MornyCoeur.extra(), chatId, messageId); - else TelegramStickers.echoStickerByID(id, MornyCoeur.extra(), chatId, messageId); - } - - /** - * Subcommand /info runtime. - * - * @see #SUB_RUNTIME - * - * @since 1.0.0-alpha4 - */ - public static void echoRuntime (@Nonnull Update event) { - MornyCoeur.extra().exec(new SendMessage( - event.message().chat().id(), - String.format(""" - system: - - %s - - %s (%s) %s - java runtime: - - %s - - %s - vm memory: - - %d / %d MB - - %d cores - coeur version: - - %s - - %s - - %s [UTC] - - [%d] - continuous: - - %s - - [%d] - - %s [UTC] - - [%d]""", - // system - escapeHtml(getRuntimeHostName()==null ? "" : getRuntimeHostName()), - escapeHtml(System.getProperty("os.name")), - escapeHtml(System.getProperty("os.arch")), - escapeHtml(System.getProperty("os.version")), - // java - escapeHtml(System.getProperty("java.vm.vendor")+"."+System.getProperty("java.vm.name")), - escapeHtml(System.getProperty("java.vm.version")), - // memory - Runtime.getRuntime().totalMemory() / 1024 / 1024, - Runtime.getRuntime().maxMemory() / 1024 / 1024, - Runtime.getRuntime().availableProcessors(), - // version - getVersionAllFullTagHtml(), - escapeHtml(MornySystem.getJarMd5()), - escapeHtml(formatDate(BuildConfig.CODE_TIMESTAMP, 0)), - BuildConfig.CODE_TIMESTAMP, - // continuous - escapeHtml(formatDuration(System.currentTimeMillis() - MornyCoeur.coeurStartTimestamp)), - System.currentTimeMillis() - MornyCoeur.coeurStartTimestamp, - escapeHtml(formatDate(MornyCoeur.coeurStartTimestamp, 0)), - MornyCoeur.coeurStartTimestamp - ) - ).replyToMessageId(event.message().messageId()).parseMode(ParseMode.HTML)); - } - - /** - * Subcommand /info version or /info v. - * - * @see #SUB_VERSION - * @see #SUB_VERSION_2 - * - * @since 1.0.0-alpha4 - */ - public static void echoVersion (@Nonnull Update event) { - MornyCoeur.extra().exec(new SendMessage( - event.message().chat().id(), - String.format( - """ - version: - - Morny %s - - %s%s%s - core md5_hash: - - %s - coding timestamp: - - %d - - %s [UTC]""", - escapeHtml(MornySystem.CODENAME.toUpperCase()), - escapeHtml(MornySystem.VERSION_BASE), - MornySystem.isUseDelta() ? String.format("-δ%s", escapeHtml(Objects.requireNonNull(MornySystem.VERSION_DELTA))) : "", - MornySystem.isGitBuild() ? "\n- git "+getVersionGitTagHtml() : "", - escapeHtml(MornySystem.getJarMd5()), - BuildConfig.CODE_TIMESTAMP, - escapeHtml(formatDate(BuildConfig.CODE_TIMESTAMP, 0)) - ) - ).replyToMessageId(event.message().messageId()).parseMode(ParseMode.HTML)); - } - - /** - * 取得 {@link MornySystem} 的 git commit 相关版本信息的 HTML 格式化标签. - * - * @return 格式类似于 {@code 28e8c82a.δ} 的以 HTML 方式格式化的版本号组件。 - * 其中 {@code .δ} 对应着 {@link MornySystem#isCleanBuild}; - * commit tag 字段如果支援 {@link MornySystem#currentCodePath} 则会以链接形式解析,否则则为 code 格式 - * 为了对 telegram api html 格式兼容所以不支援嵌套链接与code标签。 - * 如果 {@link MornySystem#isGitBuild} 为 {@link false},则方法会返回 {@link ""} - * - * @since 1.0.0-beta2 - */ - @Nonnull - public static String getVersionGitTagHtml () { - if (!MornySystem.isGitBuild()) return ""; - final StringBuilder g = new StringBuilder(); - final String cp = MornySystem.currentCodePath(); - if (cp == null) g.append(String.format("%s", BuildConfig.COMMIT.substring(0, 8))); - else g.append(String.format("%s", MornySystem.currentCodePath(), BuildConfig.COMMIT.substring(0, 8))); - if (!MornySystem.isCleanBuild()) g.append(".δ"); - return g.toString(); - } - - /** - * 取得完整 Morny 版本的 HTML 格式化标签. - *

- * 相比于 {@link MornySystem#VERSION_FULL},这个版本号还包含了 {@link MornySystem#CODENAME 版本 codename}。 - * 各个部分也被以 HTML 的格式进行了格式化以可以更好的在富文本中插入使用. - * @return 基于 HTML 标签进行了格式化了的类似于 - * {@link MornySystem#VERSION_BASE 5.38.2-alpha1}{@link MornySystem#isUseDelta() -δ}{@link MornySystem#VERSION_DELTA tt}{@link MornySystem#isGitBuild() +git.}{@link #getVersionGitTagHtml() 28e8c82a.δ}*{@link MornySystem#CODENAME TOKYO} - * 的版本号。 - * @since 1.0.0-beta2 - */ - @Nonnull - public static String getVersionAllFullTagHtml () { - final StringBuilder v = new StringBuilder(); - v.append("").append(MornySystem.VERSION_BASE).append(""); - if (MornySystem.isUseDelta()) v.append("-δ").append(MornySystem.VERSION_DELTA).append(""); - if (MornySystem.isGitBuild()) v.append("+git.").append(getVersionGitTagHtml()); - v.append("*").append(MornySystem.CODENAME.toUpperCase()).append(""); - return v.toString(); - } - - /** - * 获取 coeur 运行时的宿主机的主机名 - * @return coeur 宿主机主机名,或者 {@link null} 表示获取失败 - */ - @Nullable - public static String getRuntimeHostName () { - try { - return InetAddress.getLocalHost().getHostName(); - } catch (UnknownHostException e) { - return null; - } - } - - /** - * Get the about-pic (intro picture or featured image) of Morny. - * - * @return the Telegram file binary data of the about-pic. - * @throws IllegalStateException {@link TelegramImages.AssetsFileImage#get() get() image data} may - * throws {@link IllegalStateException} while read error. - */ - @Nonnull - public static byte[] getAboutPic () { - return TelegramImages.IMG_ABOUT.get(); - } - - private static void echo404 (@Nonnull Update event) { - MornyCoeur.extra().exec(new SendSticker( - event.message().chat().id(), - TelegramStickers.ID_404 - ).replyToMessageId(event.message().messageId())); - } - - /** - * The formatted about links of Morny Cono and Morny Coeur. - *

- * With the Telegram HTML formatting, used in /info and /start. - * Provided the end user the links that can find resources about Morny. - */ - @Nonnull - public static String getMornyAboutLinksHTML () { - return """ - source code | backup - 反馈 / issue tracker - 使用说明书 / user guide & docs""".formatted( - MornyAbout.MORNY_SOURCECODE_LINK, MornyAbout.MORNY_SOURCECODE_SELF_HOSTED_MIRROR_LINK, - MornyAbout.MORNY_ISSUE_TRACKER_LINK, - MornyAbout.MORNY_USER_GUIDE_LINK - ); - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/command/Nbnhhsh.java b/src/main/java/cc/sukazyo/cono/morny/bot/command/Nbnhhsh.java deleted file mode 100644 index 20adb23..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/bot/command/Nbnhhsh.java +++ /dev/null @@ -1,80 +0,0 @@ -package cc.sukazyo.cono.morny.bot.command; - -import cc.sukazyo.cono.morny.data.TelegramStickers; -import cc.sukazyo.cono.morny.util.tgapi.InputCommand; -import com.pengrad.telegrambot.model.Update; -import com.pengrad.telegrambot.model.request.ParseMode; -import com.pengrad.telegrambot.request.SendMessage; - -import cc.sukazyo.cono.morny.MornyCoeur; -import cc.sukazyo.cono.morny.data.NbnhhshQuery; -import com.pengrad.telegrambot.request.SendSticker; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import static cc.sukazyo.cono.morny.util.CommonConvert.stringsConnecting; -import static cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml; - -public class Nbnhhsh implements ITelegramCommand { - - @Nonnull @Override public String getName () { return "nbnhhsh"; } - @Nullable @Override public String[] getAliases () { return null; } - @Nonnull @Override public String getParamRule () { return "[text]"; } - @Nonnull @Override public String getDescription () { return "检索文本内 nbnhhsh 词条"; } - - @Override - public void execute (@Nonnull InputCommand command, @Nonnull Update event) { - - class TagNoContent extends Exception {} - try { - - String queryTarget; - if (event.message().replyToMessage() != null && event.message().replyToMessage().text() != null) - queryTarget = event.message().replyToMessage().text(); - else if (command.hasArgs()) - queryTarget = stringsConnecting(command.getArgs(), " ", 0, command.getArgs().length-1); - else { - throw new TagNoContent(); - } - - NbnhhshQuery.GuessResult response = NbnhhshQuery.sendGuess(queryTarget); - - StringBuilder message = new StringBuilder("## Result of nbnhhsh query :"); - - for (NbnhhshQuery.Word word : response.words) { - if (word.trans != null && word.trans.length == 0) word.trans = null; - if (word.inputting != null && word.inputting.length == 0) word.inputting = null; - if (word.trans == null && word.inputting == null) continue; - message.append("\n\n[[ ").append(escapeHtml(word.name)).append(" ]]"); - if (word.trans != null) for (String trans : word.trans) { - message.append("\n* ").append(escapeHtml(trans)).append(""); - } - if (word.inputting != null) { - if (word.trans != null) message.append("\n"); - message.append(" maybe:"); - for (String trans : word.inputting) { - message.append("\n` ").append(escapeHtml(trans)).append(""); - } - } - } - - MornyCoeur.extra().exec(new SendMessage( - event.message().chat().id(), - message.toString() - ).parseMode(ParseMode.HTML).replyToMessageId(event.message().messageId())); - - } catch (TagNoContent tag) { - MornyCoeur.extra().exec(new SendSticker( - event.message().chat().id(), TelegramStickers.ID_404 - ).replyToMessageId(event.message().messageId())); - } catch (Exception e) { - MornyCoeur.extra().exec(new SendMessage( - event.message().chat().id(), - "[Exception] in query:\n" + escapeHtml(e.getMessage()) + "" - ).parseMode(ParseMode.HTML).replyToMessageId(event.message().messageId())); - } - - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/command/Testing.java b/src/main/java/cc/sukazyo/cono/morny/bot/command/Testing.java deleted file mode 100644 index 8039ce7..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/bot/command/Testing.java +++ /dev/null @@ -1,36 +0,0 @@ -package cc.sukazyo.cono.morny.bot.command; - -import cc.sukazyo.cono.morny.MornyCoeur; -import cc.sukazyo.cono.morny.util.tgapi.InputCommand; -import com.pengrad.telegrambot.model.Update; -import com.pengrad.telegrambot.model.request.ParseMode; -import com.pengrad.telegrambot.request.SendMessage; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -public class Testing implements ISimpleCommand { - - @Nonnull - @Override - public String getName () { - return "test"; - } - - @Nullable - @Override - public String[] getAliases () { - return null; - } - - @Override - public void execute (@Nonnull InputCommand command, @Nonnull Update event) { - - MornyCoeur.extra().exec(new SendMessage( - event.message().chat().id(), - "Just a TEST command." - ).replyToMessageId(event.message().messageId()).parseMode(ParseMode.HTML)); - - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/command/喵呜.java b/src/main/java/cc/sukazyo/cono/morny/bot/command/喵呜.java deleted file mode 100644 index 692ce2a..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/bot/command/喵呜.java +++ /dev/null @@ -1,82 +0,0 @@ -package cc.sukazyo.cono.morny.bot.command; - -import cc.sukazyo.cono.morny.MornyCoeur; -import cc.sukazyo.cono.morny.data.TelegramStickers; -import cc.sukazyo.cono.morny.util.tgapi.InputCommand; -import com.pengrad.telegrambot.model.Message; -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 javax.annotation.Nonnull; -import javax.annotation.Nullable; - -/** - * WARNING that {@link cc.sukazyo.cono.morny.bot.event.OnTelegramCommand} - * 并不能够处理非 english word 字符之外的命令. - *

- * 出于这个限制,以下几个命令目前都无法使用 - * @see 抱抱 - * @see 揉揉 - * @see 蹭蹭 - * @see 贴贴 - */ -@SuppressWarnings("NonAsciiCharacters") -public class 喵呜 { - - public static class 抱抱 implements ISimpleCommand { - @Nonnull @Override public String getName () { return "抱抱"; } - @Nullable @Override public String[] getAliases () { return new String[0]; } - @Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { - replyingSet(event, "抱抱", "抱抱"); - } - } - - public static class 揉揉 implements ISimpleCommand { - @Nonnull @Override public String getName () { return "揉揉"; } - @Nullable @Override public String[] getAliases () { return new String[0]; } - @Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { - replyingSet(event, "蹭蹭", "摸摸"); - } - } - - public static class 蹭蹭 implements ISimpleCommand { - @Nonnull @Override public String getName () { return "蹭蹭"; } - @Nullable @Override public String[] getAliases () { return new String[0]; } - @Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { - replyingSet(event, "揉揉", "蹭蹭"); - } - } - - public static class 贴贴 implements ISimpleCommand { - @Nonnull @Override public String getName () { return "贴贴"; } - @Nullable @Override public String[] getAliases () { return new String[0]; } - @Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { - replyingSet(event, "贴贴", "贴贴"); - } - } - - private static void replyingSet (@Nonnull Update event, @Nonnull String whileRec, @Nonnull String whileNew) { - final boolean isNew = event.message().replyToMessage() == null; - final Message target = isNew ? event.message() : event.message().replyToMessage(); - MornyCoeur.extra().exec(new SendMessage( - event.message().chat().id(), - isNew ? whileNew : whileRec - ).replyToMessageId(target.messageId()).parseMode(ParseMode.HTML)); - } - - public static class Progynova implements ITelegramCommand { - @Nonnull @Override public String getName () { return "install"; } - @Nullable @Override public String[] getAliases () { return new String[0]; } - @Nonnull @Override public String getParamRule () { return ""; } - @Nonnull @Override public String getDescription () { return "抽取一个神秘盒子"; } - @Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { - MornyCoeur.extra().exec(new SendSticker( - event.message().chat().id(), - TelegramStickers.ID_PROGYNOVA - ).replyToMessageId(event.message().messageId())); - } - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/command/私わね.java b/src/main/java/cc/sukazyo/cono/morny/bot/command/私わね.java deleted file mode 100644 index 6006c0d..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/bot/command/私わね.java +++ /dev/null @@ -1,40 +0,0 @@ -package cc.sukazyo.cono.morny.bot.command; - -import cc.sukazyo.cono.morny.MornyCoeur; -import cc.sukazyo.cono.morny.util.tgapi.InputCommand; -import com.pengrad.telegrambot.model.Update; -import com.pengrad.telegrambot.request.SendMessage; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import static cc.sukazyo.cono.morny.util.CommonRandom.probabilityTrue; - -@SuppressWarnings("NonAsciiCharacters") -public class 私わね implements ISimpleCommand { - - @Nonnull - @Override public String getName () { return "me"; } - - @Nullable - @Override public String[] getAliases () { return null; } - - @Override - public void execute (@Nonnull InputCommand command, @Nonnull Update event) { - if (probabilityTrue(521)) { - // 可以接入未来的心情系统(如果有的话) -// final String text = switch (ThreadLocalRandom.current().nextInt(11)) { -// case 0,7,8,9,10 -> "才不是"; -// case 1,2,3,6 -> "才不是!"; -// case 4,5 -> "才不是.."; -// default -> throw new IllegalStateException("Unexpected random value in 私わね command."); -// }; - final String text = "/打假"; - MornyCoeur.extra().exec(new SendMessage( - event.message().chat().id(), - text - ).replyToMessageId(event.message().messageId())); - } - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/event/OnCallMe.java b/src/main/java/cc/sukazyo/cono/morny/bot/event/OnCallMe.java deleted file mode 100644 index 89ed0fc..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/bot/event/OnCallMe.java +++ /dev/null @@ -1,181 +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.data.TelegramStickers; -import cc.sukazyo.cono.morny.util.CommonFormat; -import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape; -import cc.sukazyo.cono.morny.util.tgapi.formatting.TGToString; -import com.pengrad.telegrambot.model.Chat; -import com.pengrad.telegrambot.model.Message; -import com.pengrad.telegrambot.model.Update; -import com.pengrad.telegrambot.model.request.ParseMode; -import com.pengrad.telegrambot.request.ForwardMessage; -import com.pengrad.telegrambot.request.GetChat; -import com.pengrad.telegrambot.request.SendMessage; -import com.pengrad.telegrambot.request.SendSticker; -import com.pengrad.telegrambot.response.SendResponse; - -import javax.annotation.Nonnull; - -/** - * 通过 bot 呼叫主人的事件监听管理类 - * @since 0.4.2.1 - */ -public class OnCallMe extends EventListener { - - /** - * 主人的 telegram user id,同时被用于 chat id
- * 跟随 {@link cc.sukazyo.cono.morny.MornyConfig#trustedMaster} 的值 - * @since 0.4.2.1 - */ - private static final long ME = MornyCoeur.config().trustedMaster; - - /** - * 监听私聊 bot 的消息进行呼叫关键字匹配。 - * 如果成功,将会执行呼叫函数,并向呼叫者回显{@link TelegramStickers#ID_WAITING "已呼叫"贴纸} - * - * @param update 事件基础参数,消息事件所属的 tgapi:update 对象 - * @return 事件基础返回值,是否已完成处理事件:
- * 如果匹配到呼叫,则返回{@code true},反之返回{@code false} - */ - @Override - public boolean onMessage (@Nonnull Update update) { - if (update.message().text() == null) - return false; - if (update.message().chat().type() != Chat.Type.Private) - return false; - switch (update.message().text().toLowerCase()) { - case "steam", "sbeam", "sdeam" -> - requestSteamJoin(update); - case "hana paresu", "花宫", "内群" -> - requestHanaParesuJoin(update); - case "dinner", "lunch", "breakfast", "meal", "eating", "安妮今天吃什么" -> - requestLastDinner(update); - default -> { - if (update.message().text().startsWith("cc::")) { - requestCustomCall(update); - break; - } - return false; - } - } - MornyCoeur.extra().exec(new SendSticker( - update.message().chat().id(), - TelegramStickers.ID_SENT - ).replyToMessageId(update.message().messageId()) - ); - return true; - } - - /** - * 执行 steam library 呼叫
- * 将会向 {@link #ME} 发送 - * - * @param event 执行呼叫的tg事件 - */ - private static void requestSteamJoin (Update event) { - MornyCoeur.extra().exec(new SendMessage( - ME, String.format( - """ - request STEAM LIBRARY - from %s""", - TGToString.as(event.message().from()).fullnameRefHtml() - ) - ).parseMode(ParseMode.HTML)); - } - - /** - * 执行花宫呼叫
- * 将会向 {@link #ME} 发送 - * - * @param event 执行呼叫的tg事件 - */ - private static void requestHanaParesuJoin (Update event) { - MornyCoeur.extra().exec(new SendMessage( - ME, String.format( - """ - request Hana Paresu - from %s""", - TGToString.as(event.message().from()).fullnameRefHtml() - ) - ).parseMode(ParseMode.HTML)); - } - - /** - * 对访问最近一次的饭局的请求进行回复
- * - * @param event 执行呼叫的tg事件 - */ - private static void requestLastDinner (Update event) { - boolean isAllowed = false; - Message lastDinnerData = null; - if (MornyCoeur.trustedInstance().isTrustedForDinnerRead(event.message().from().id())) { - lastDinnerData = MornyCoeur.extra().exec(new GetChat(MornyCoeur.config().dinnerChatId)).chat().pinnedMessage(); - SendResponse sendResp = MornyCoeur.extra().exec(new ForwardMessage( - event.message().from().id(), - lastDinnerData.forwardFromChat().id(), - lastDinnerData.forwardFromMessageId() - )); - MornyCoeur.extra().exec(new SendMessage( - event.message().from().id(), - String.format("on %s [UTC+8]\n- %s before", - MsgEscape.escapeHtml( - CommonFormat.formatDate((long)lastDinnerData.forwardDate()*1000, 8) - ), MsgEscape.escapeHtml( - CommonFormat.formatDuration(System.currentTimeMillis()-(long)lastDinnerData.forwardDate()*1000) - ) - ) - ).replyToMessageId(sendResp.message().messageId()).parseMode(ParseMode.HTML)); - isAllowed = true; - } else { - MornyCoeur.extra().exec(new SendSticker( - event.message().from().id(), - TelegramStickers.ID_403 - ).replyToMessageId(event.message().messageId())); - } - MornyCoeur.extra().exec(new SendMessage( - ME, String.format( - """ - request Last Annie Dinner - from %s - %s""", - TGToString.as(event.message().from()).fullnameRefHtml(), - isAllowed ? "Allowed and returned " + String.format( - "https://t.me/c/%d/%d", Math.abs(lastDinnerData.forwardFromChat().id()+1000000000000L), lastDinnerData.forwardFromMessageId() - ) : "Forbidden by perm check." - ) - ).parseMode(ParseMode.HTML)); - } - - /** - * 执行自定义呼叫
- * 将会向 {@link #ME} 发送一个 request 数据消息和转发的原始请求消息
- *
- * known issue

    - *
  • 无法处理与转发带有媒体的消息
  • - *
- *
- * 现在你可以通过这个 bot 来呼叫主人(sukazyo)任何事情了 —— - * 但是直接私聊sukazyo不好吗 - * - * @param event 执行呼叫的tg事件 - * @since 0.4.2.2 - */ - private static void requestCustomCall (Update event) { - MornyCoeur.extra().exec(new SendMessage( - ME, String.format( - """ - request [???] - from %s""", - TGToString.as(event.message().from()).fullnameRefHtml() - ) - ).parseMode(ParseMode.HTML)); - MornyCoeur.extra().exec(new ForwardMessage( - ME, - event.message().chat().id(), - event.message().messageId() - )); - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/event/OnInlineQueries.java b/src/main/java/cc/sukazyo/cono/morny/bot/event/OnInlineQueries.java deleted file mode 100644 index ed06f0b..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/bot/event/OnInlineQueries.java +++ /dev/null @@ -1,47 +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.bot.api.InlineQueryUnit; -import com.pengrad.telegrambot.model.Update; -import com.pengrad.telegrambot.model.request.InlineQueryResult; -import com.pengrad.telegrambot.request.AnswerInlineQuery; - -import javax.annotation.Nonnull; -import java.util.List; - -/** - * telegram inlineQuery 功能的处理类, - * 也是一个 InlineQueryManager(还没做) - * - * @since 0.4.1.3 - */ -public class OnInlineQueries extends EventListener { - - /** - * @since 0.4.1.3 - */ - @Override - public boolean onInlineQuery (@Nonnull Update update) { - - List> results = MornyCoeur.queryManager().query(update); - - int cacheTime = Integer.MAX_VALUE; - boolean isPersonal = InlineQueryUnit.DEFAULT_INLINE_PERSONAL_RESP; - InlineQueryResult[] inlineQueryResults = new InlineQueryResult[results.size()]; - for (int i = 0; i < results.size(); i++) { - inlineQueryResults[i] = results.get(i).result; - if (cacheTime > results.get(i).cacheTime()) cacheTime = results.get(i).cacheTime(); - if (results.get(i).isPersonal()) isPersonal = true; - } - - if (results.size() == 0) return false; - - MornyCoeur.extra().exec(new AnswerInlineQuery( - update.inlineQuery().id(), inlineQueryResults - ).cacheTime(cacheTime).isPersonal(isPersonal)); - return true; - - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/event/OnUserRandoms.java b/src/main/java/cc/sukazyo/cono/morny/bot/event/OnUserRandoms.java deleted file mode 100644 index b1deec4..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/bot/event/OnUserRandoms.java +++ /dev/null @@ -1,42 +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.regex.Matcher; -import java.util.regex.Pattern; - -import static cc.sukazyo.cono.morny.util.CommonRandom.iif; - -public class OnUserRandoms extends EventListener { - - private static final Pattern USER_OR_QUERY = Pattern.compile("(.+)(?:还是|or)(.+)"); - private static final Pattern USER_IF_QUERY = Pattern.compile("(.+)[吗?|?]+$"); - - @Override - public boolean onMessage (@Nonnull Update update) { - - if (update.message().text() == null) return false; - if (!update.message().text().startsWith("/")) return false; - - final String query = update.message().text().substring(1); - String result = null; - Matcher matcher; - if ((matcher = USER_OR_QUERY.matcher(query)).find()) { - result = iif() ? matcher.group(1) : matcher.group(2); - } else if ((matcher = USER_IF_QUERY.matcher(query)).matches()) { - result = (iif()?"":"不") + matcher.group(1); - } - - if (result == null) return false; - MornyCoeur.extra().exec(new SendMessage( - update.message().chat().id(), result - ).replyToMessageId(update.message().messageId())); - return true; - - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/event/OnUserSlashAction.java b/src/main/java/cc/sukazyo/cono/morny/bot/event/OnUserSlashAction.java deleted file mode 100644 index cf1910b..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/bot/event/OnUserSlashAction.java +++ /dev/null @@ -1,84 +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.UniversalCommand; -import cc.sukazyo.cono.morny.util.tgapi.formatting.TGToString; - -import com.pengrad.telegrambot.model.Message; -import com.pengrad.telegrambot.model.Update; -import com.pengrad.telegrambot.model.request.ParseMode; -import com.pengrad.telegrambot.request.SendMessage; - -import javax.annotation.Nonnull; - -import static cc.sukazyo.cono.morny.util.CommonConvert.stringsConnecting; -import static cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml; - -public class OnUserSlashAction extends EventListener { - - @Override - public boolean onMessage (@Nonnull Update event) { - final String text = event.message().text(); - if (text == null) return false; - - if (text.startsWith("/")) - { - - /// Due to @Lapis_Apple, we stopped slash action function at .DP7 groups. - /// It may be enabled after some updates when the function will not be conflicted to other bots. - // if (event.message().chat().id() == ) return false; -//{ if (event.message().chat().title() != null && event.message().chat().title().contains(".DP7")) { -// logger.info(String.format(""" -// Chat slash action ignored due to the following keyword. -// - %s -// - ".DP7\"""", -// TGToString.as(event.message().chat()).toStringFullNameId() -// )); -// return false; -// } - - final String[] action = UniversalCommand.format(text); - action[0] = action[0].substring(1); - - if (action[0].matches("^\\w+(@\\w+)?$")) { - return false; // 忽略掉 Telegram 命令格式的输入 - } else if (action[0].contains("/")) { - return false; // 忽略掉疑似目录格式的输入 - } - - final boolean isHardParse = "".equals(action[0]); - /* 忽略空数据 */ if (isHardParse && action.length < 2) { return false; } - final String verb = isHardParse ? action[1] : action[0]; - final boolean hasObject = action.length != (isHardParse?2:1); - final String object = - hasObject ? - stringsConnecting(action, " ", isHardParse?2:1, action.length-1) : - ""; - final Message origin = event.message(); - final Message target = (event.message().replyToMessage() == null ? ( - origin - ): ( - event.message().replyToMessage() - )); - - MornyCoeur.extra().exec(new SendMessage( - event.message().chat().id(), - String.format( - "%s %s%s %s %s!", - TGToString.as(origin).getSenderFirstNameRefHtml(), - escapeHtml(verb), escapeHtml((hasObject?"":"了")), - origin==target ? - "自己" : - TGToString.as(target).getSenderFirstNameRefHtml(), - escapeHtml(hasObject ? object+" " : "") - ) - ).parseMode(ParseMode.HTML).replyToMessageId(event.message().messageId())); - - return true; - - } - return false; - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/query/ITelegramQuery.java b/src/main/java/cc/sukazyo/cono/morny/bot/query/ITelegramQuery.java deleted file mode 100644 index c79ab37..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/bot/query/ITelegramQuery.java +++ /dev/null @@ -1,15 +0,0 @@ -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; - -import java.util.List; - -public interface ITelegramQuery { - - @Nullable - List> query (Update event); - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/query/MornyQueries.java b/src/main/java/cc/sukazyo/cono/morny/bot/query/MornyQueries.java deleted file mode 100644 index b0dc135..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/bot/query/MornyQueries.java +++ /dev/null @@ -1,31 +0,0 @@ -package cc.sukazyo.cono.morny.bot.query; - -import cc.sukazyo.cono.morny.bot.api.InlineQueryUnit; -import com.pengrad.telegrambot.model.Update; - -import javax.annotation.Nonnull; -import java.util.ArrayList; -import java.util.List; - -public class MornyQueries { - - private final List queryInstances = new ArrayList<>(); - - public MornyQueries () { - queryInstances.add(new RawText()); - queryInstances.add(new MyInformation()); - queryInstances.add(new ShareToolTwitter()); - queryInstances.add(new ShareToolBilibili()); - } - - @Nonnull - public List> query (@Nonnull Update event) { - final List> results = new ArrayList<>(); - for (ITelegramQuery instance : queryInstances) { - final List> r = instance.query(event); - if (r!=null) results.addAll(r); - } - return results; - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/query/MyInformation.java b/src/main/java/cc/sukazyo/cono/morny/bot/query/MyInformation.java deleted file mode 100644 index 7921174..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/bot/query/MyInformation.java +++ /dev/null @@ -1,35 +0,0 @@ -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; -import com.pengrad.telegrambot.model.request.InlineQueryResultArticle; -import com.pengrad.telegrambot.model.request.InputTextMessageContent; -import com.pengrad.telegrambot.model.request.ParseMode; - -import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramUserInformation; - -import java.util.Collections; -import java.util.List; - -import static cc.sukazyo.cono.morny.util.tgapi.formatting.NamedUtils.inlineIds; - -public class MyInformation implements ITelegramQuery { - - public static final String ID_PREFIX = "[morny/info/me]"; - public static final String TITLE = "My Account Information"; - - @Override - @Nullable - public List> query(Update event) { - if (!(event.inlineQuery().query() == null || "".equals(event.inlineQuery().query()))) return null; - return Collections.singletonList(new InlineQueryUnit<>(new InlineQueryResultArticle( - inlineIds(ID_PREFIX), TITLE, - new InputTextMessageContent( - TelegramUserInformation.informationOutputHTML(event.inlineQuery().from()) - ).parseMode(ParseMode.HTML) - )).isPersonal(true).cacheTime(10)); - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/query/RawText.java b/src/main/java/cc/sukazyo/cono/morny/bot/query/RawText.java deleted file mode 100644 index a773f6b..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/bot/query/RawText.java +++ /dev/null @@ -1,31 +0,0 @@ -package cc.sukazyo.cono.morny.bot.query; - -import cc.sukazyo.cono.morny.bot.api.InlineQueryUnit; - -import javax.annotation.Nullable; - -import com.pengrad.telegrambot.model.Update; -import com.pengrad.telegrambot.model.request.InlineQueryResultArticle; -import com.pengrad.telegrambot.model.request.InputTextMessageContent; - -import java.util.Collections; -import java.util.List; - -import static cc.sukazyo.cono.morny.util.tgapi.formatting.NamedUtils.inlineIds; - -public class RawText implements ITelegramQuery { - - public static final String ID_PREFIX = "[morny/r/text]"; - public static final String TITLE = "Raw Text"; - - @Override - @Nullable - public List> query (Update event) { - if (event.inlineQuery().query() == null || "".equals(event.inlineQuery().query())) return null; - return Collections.singletonList(new InlineQueryUnit<>(new InlineQueryResultArticle( - inlineIds(ID_PREFIX, event.inlineQuery().query()), TITLE, - new InputTextMessageContent(event.inlineQuery().query()) - ))); - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/query/ShareToolBilibili.java b/src/main/java/cc/sukazyo/cono/morny/bot/query/ShareToolBilibili.java deleted file mode 100644 index da6c2fa..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/bot/query/ShareToolBilibili.java +++ /dev/null @@ -1,80 +0,0 @@ -package cc.sukazyo.cono.morny.bot.query; - -import cc.sukazyo.cono.morny.bot.api.InlineQueryUnit; -import cc.sukazyo.cono.morny.util.BiliTool; -import com.pengrad.telegrambot.model.Update; -import com.pengrad.telegrambot.model.request.InlineQueryResultArticle; -import com.pengrad.telegrambot.model.request.InputTextMessageContent; -import com.pengrad.telegrambot.model.request.ParseMode; - -import javax.annotation.Nullable; -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import static cc.sukazyo.cono.morny.Log.logger; -import static cc.sukazyo.cono.morny.util.tgapi.formatting.NamedUtils.inlineIds; - -public class ShareToolBilibili implements ITelegramQuery { - - public static final String TITLE_BILI_AV = "[bilibili] Share video / av"; - public static final String TITLE_BILI_BV = "[bilibili] Share video / BV"; - public static final String ID_PREFIX_BILI_AV = "[morny/share/bili/av]"; - public static final String ID_PREFIX_BILI_BV = "[morny/share/bili/bv]"; - public static final Pattern REGEX_BILI_VIDEO = Pattern.compile("^(?:(?:https?://)?(?:www\\.)?bilibili\\.com(?:/s)?/video/((?:av|AV)(\\d{1,12})|(?:bv|BV)([A-HJ-NP-Za-km-z1-9]{10}))/?(\\?(?:p=(\\d+))?.*)?|(?:av|AV)(\\d{1,12})|(?:bv|BV)([A-HJ-NP-Za-km-z1-9]{10}))$"); - - private static final String SHARE_FORMAT_HTML = "%s"; - - @Nullable - @Override - public List> query (Update event) { - if (event.inlineQuery().query() == null) return null; - final Matcher regex = REGEX_BILI_VIDEO.matcher(event.inlineQuery().query()); - if (regex.matches()) { - - logger.debug(String.format( - "====== Share Tool Bilibili Catch ok\n1: %s\n2: %s\n3: %s\n4: %s\n5: %s\n6: %s\n7: %s", - regex.group(1), regex.group(2), regex.group(3), regex.group(4), - regex.group(5), regex.group(6), regex.group(7) - )); - - // get video id from input, also get video part id - String av = regex.group(2)==null ? regex.group(6)==null ? null : regex.group(6) : regex.group(2); - String bv = regex.group(3)==null ? regex.group(7)==null ? null : regex.group(7) : regex.group(3); - logger.trace(String.format("catch id av[%s] bv[%s]", av, bv)); - final int part = regex.group(5)==null ? -1 : Integer.parseInt(regex.group(5)); - logger.trace(String.format("catch part [%s]", part)); - if (av == null) { - assert bv != null; - av = String.valueOf(BiliTool.toAv(bv)); - logger.trace(String.format("converted bv[%s] to av[%s]", bv, av)); - } else { - bv = BiliTool.toBv(Long.parseLong(av)); - logger.trace(String.format("converted av[%s] to bv[%s]", av, bv)); - } - // build standard share links - final String linkPartParam = part==-1 ? "" : "?p="+part; - final String linkAv = "https://www.bilibili.com/video/av"+av + linkPartParam; - final String linkBv = "https://www.bilibili.com/video/BV"+bv + linkPartParam; - final String idAv = "av"+av; - final String idBv = "BV"+bv; - logger.trace("built all data."); - - // build share message element - List> result = new ArrayList<>(); - result.add(new InlineQueryUnit<>(new InlineQueryResultArticle( - inlineIds(ID_PREFIX_BILI_AV+av), TITLE_BILI_AV+av, - new InputTextMessageContent(String.format(SHARE_FORMAT_HTML, linkAv, idAv)).parseMode(ParseMode.HTML) - ))); - result.add(new InlineQueryUnit<>(new InlineQueryResultArticle( - inlineIds(ID_PREFIX_BILI_BV+bv), TITLE_BILI_BV+bv, - new InputTextMessageContent(String.format(SHARE_FORMAT_HTML, linkBv, idBv)).parseMode(ParseMode.HTML) - ))); - return result; - - } - return null; - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/query/ShareToolTwitter.java b/src/main/java/cc/sukazyo/cono/morny/bot/query/ShareToolTwitter.java deleted file mode 100644 index 9c50d6f..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/bot/query/ShareToolTwitter.java +++ /dev/null @@ -1,50 +0,0 @@ -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; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import static cc.sukazyo.cono.morny.util.tgapi.formatting.NamedUtils.inlineIds; - -public class ShareToolTwitter implements ITelegramQuery { - - public static final String TITLE_VX = "[tweet] Share as VxTwitter"; - public static final String TITLE_VX_COMBINED = "[tweet] Share as VxTwitter(combination)"; - public static final String ID_PREFIX_VX = "[morny/share/twitter/vxtwi]"; - public static final String ID_PREFIX_VX_COMBINED = "[morny/share/twitter/vxtwi_combine]"; - - public static final Pattern REGEX_TWEET_LINK = Pattern.compile( - "^(?:https?://)?((?:(?:c\\.)?vx|fx|www\\.)?twitter\\.com)/((\\w+)/status/(\\d+)(?:/photo/(\\d+))?)/?(\\?[\\w&=-]+)?$"); - - @Nullable - @Override - public List> query (@Nonnull Update event) { - if (event.inlineQuery().query() == null) return null; - final Matcher regex = REGEX_TWEET_LINK.matcher(event.inlineQuery().query()); - if (regex.matches()) { - - List> result = new ArrayList<>(); - - result.add(new InlineQueryUnit<>(new InlineQueryResultArticle( - inlineIds(ID_PREFIX_VX+event.inlineQuery().query()), TITLE_VX, - String.format("https://vxtwitter.com/%s", regex.group(2)) - ))); - result.add(new InlineQueryUnit<>(new InlineQueryResultArticle( - inlineIds(ID_PREFIX_VX_COMBINED+event.inlineQuery().query()), TITLE_VX_COMBINED, - String.format("https://c.vxtwitter.com/%s", regex.group(2)) - ))); - - return result; - - } - return null; - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/data/ip186/IP186QueryHandler.java b/src/main/java/cc/sukazyo/cono/morny/data/ip186/IP186QueryHandler.java deleted file mode 100644 index 0f60d81..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/data/ip186/IP186QueryHandler.java +++ /dev/null @@ -1,89 +0,0 @@ -package cc.sukazyo.cono.morny.data.ip186; - -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -import okhttp3.ResponseBody; - -import javax.annotation.Nonnull; -import java.io.IOException; - -/** - * 通过 {@value #SITE_URL} 进行 {@link #queryIp ip}/{@link #queryWhois whois} 数据查询的工具类 - * - * @since 0.4.2.10 - */ -public class IP186QueryHandler { - - /** - * 请求所使用的 HTTP API 站点链接 - * @since 0.4.2.10 - */ - public static final String SITE_URL = "https://ip.186526.xyz/"; - - /** - * 进行 {@link #queryIp ip 查询}时所使用的 API 参数.
- * 目的使 API 直接返回原始数据 - */ - private static final String QUERY_IP_PARAM = "type=json&format=true"; - - /** - * 进行 {@link #queryWhois whois 查询}时所使用的 API 参数.
- * 目的使 API 直接返回原始数据 - */ - private static final String QUERY_WHOIS_PARAM = "type=plain"; - - /** 请求时使用的 OkHttp 请求工具实例 */ - private static final OkHttpClient httpClient = new OkHttpClient(); - - /** - * 通过 {@value #SITE_URL} 获取 ip 信息. - * @see #QUERY_IP_PARAM 发送请求时所使用的 API 参数 - * @param ip 需要进行查询的 ip - * @return 查询结果。data 根据 {@value #SITE_URL} 的规则以 json 序列化 - * @throws IOException 任何请求或解析错误 - */ - @Nonnull - public static IP186QueryResponse queryIp (String ip) throws IOException { - final String requestUrl = SITE_URL + ip; - return commonQuery(requestUrl, QUERY_IP_PARAM); - } - - /** - * 通过 {@value #SITE_URL} 获取域名信息. - * @see #QUERY_WHOIS_PARAM 发送请求时所使用的 API 参数 - * @param domain 需要进行查询的域名 - * @return 查询结果。data 根据 {@value #SITE_URL} 的规则以 plain 序列化 - * @throws IOException 任何请求或解析错误 - */ - @Nonnull - public static IP186QueryResponse queryWhois (String domain) throws IOException { - final String requestUrl = SITE_URL + "whois/" + domain; - return commonQuery(requestUrl, QUERY_WHOIS_PARAM); - } - - /** - * 将 {@link #queryWhois(String)} 的结果进行裁剪. - *
- * 将会删除返回内容中 {@code >>> XXX <<<} 行以后的注释串, - * 以达到只保留重要信息的目的。 - * - * @see #queryWhois(String) - */ - @Nonnull - public static IP186QueryResponse queryWhoisPretty (String domain) throws IOException { - final IP186QueryResponse raw = queryWhois(domain); - return new IP186QueryResponse(raw.url(), raw.body().substring(0, raw.body().indexOf("<<<")+3)); - } - - @Nonnull - private static IP186QueryResponse commonQuery (String requestUrl, String queryIpParam) throws IOException { - Request request = new Request.Builder().url(requestUrl + "?" + queryIpParam).build(); - try (Response response = httpClient.newCall(request).execute()) { - final ResponseBody body = response.body(); - if (body == null) throw new IOException("Null body."); - return new IP186QueryResponse(requestUrl, body.string()); - } - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/data/ip186/IP186QueryResponse.java b/src/main/java/cc/sukazyo/cono/morny/data/ip186/IP186QueryResponse.java deleted file mode 100644 index f30fb3d..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/data/ip186/IP186QueryResponse.java +++ /dev/null @@ -1,11 +0,0 @@ -package cc.sukazyo.cono.morny.data.ip186; - -/** - * {@link IP186QueryHandler} 的请求结果数据的通用封装类. - * - * @since 0.4.2.10 - * @param url 请求数据的人类可读的来源链接,并非api链接 - * @param body API 传回的数据内容 - */ -public record IP186QueryResponse(String url, String body) { -} diff --git a/src/main/java/cc/sukazyo/cono/morny/Log.java b/src/main/old/cc/sukazyo/cono/morny/Log.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/Log.java rename to src/main/old/cc/sukazyo/cono/morny/Log.java diff --git a/src/main/java/cc/sukazyo/cono/morny/MornyAbout.java b/src/main/old/cc/sukazyo/cono/morny/MornyAbout.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/MornyAbout.java rename to src/main/old/cc/sukazyo/cono/morny/MornyAbout.java diff --git a/src/main/java/cc/sukazyo/cono/morny/MornyAssets.java b/src/main/old/cc/sukazyo/cono/morny/MornyAssets.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/MornyAssets.java rename to src/main/old/cc/sukazyo/cono/morny/MornyAssets.java diff --git a/src/main/java/cc/sukazyo/cono/morny/MornyCoeur.java b/src/main/old/cc/sukazyo/cono/morny/MornyCoeur.java similarity index 99% rename from src/main/java/cc/sukazyo/cono/morny/MornyCoeur.java rename to src/main/old/cc/sukazyo/cono/morny/MornyCoeur.java index d891a84..517332d 100644 --- a/src/main/java/cc/sukazyo/cono/morny/MornyCoeur.java +++ b/src/main/old/cc/sukazyo/cono/morny/MornyCoeur.java @@ -58,7 +58,7 @@ public class MornyCoeur { * morny 主程序启动时间
* 用于统计数据 */ - public static final long coeurStartTimestamp = ServerMain.systemStartupTime; + public static final long coeurStartTimestamp = ServerMain.systemStartupTime(); private Object whileExitReason = null; diff --git a/src/main/java/cc/sukazyo/cono/morny/MornyConfig.java b/src/main/old/cc/sukazyo/cono/morny/MornyConfig.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/MornyConfig.java rename to src/main/old/cc/sukazyo/cono/morny/MornyConfig.java diff --git a/src/main/java/cc/sukazyo/cono/morny/MornySystem.java b/src/main/old/cc/sukazyo/cono/morny/MornySystem.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/MornySystem.java rename to src/main/old/cc/sukazyo/cono/morny/MornySystem.java diff --git a/src/main/java/cc/sukazyo/cono/morny/MornyTrusted.java b/src/main/old/cc/sukazyo/cono/morny/MornyTrusted.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/MornyTrusted.java rename to src/main/old/cc/sukazyo/cono/morny/MornyTrusted.java diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/api/EventListener.java b/src/main/old/cc/sukazyo/cono/morny/bot/api/EventListener.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/bot/api/EventListener.java rename to src/main/old/cc/sukazyo/cono/morny/bot/api/EventListener.java diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/api/EventListenerManager.java b/src/main/old/cc/sukazyo/cono/morny/bot/api/EventListenerManager.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/bot/api/EventListenerManager.java rename to src/main/old/cc/sukazyo/cono/morny/bot/api/EventListenerManager.java diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/api/InlineQueryUnit.java b/src/main/old/cc/sukazyo/cono/morny/bot/api/InlineQueryUnit.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/bot/api/InlineQueryUnit.java rename to src/main/old/cc/sukazyo/cono/morny/bot/api/InlineQueryUnit.java diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/api/OnUpdate.java b/src/main/old/cc/sukazyo/cono/morny/bot/api/OnUpdate.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/bot/api/OnUpdate.java rename to src/main/old/cc/sukazyo/cono/morny/bot/api/OnUpdate.java diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/command/ISimpleCommand.java b/src/main/old/cc/sukazyo/cono/morny/bot/command/ISimpleCommand.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/bot/command/ISimpleCommand.java rename to src/main/old/cc/sukazyo/cono/morny/bot/command/ISimpleCommand.java diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/command/ITelegramCommand.java b/src/main/old/cc/sukazyo/cono/morny/bot/command/ITelegramCommand.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/bot/command/ITelegramCommand.java rename to src/main/old/cc/sukazyo/cono/morny/bot/command/ITelegramCommand.java diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyCommands.java b/src/main/old/cc/sukazyo/cono/morny/bot/command/MornyCommands.java similarity index 96% rename from src/main/java/cc/sukazyo/cono/morny/bot/command/MornyCommands.java rename to src/main/old/cc/sukazyo/cono/morny/bot/command/MornyCommands.java index e84ab3e..d3cf37f 100644 --- a/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyCommands.java +++ b/src/main/old/cc/sukazyo/cono/morny/bot/command/MornyCommands.java @@ -55,15 +55,15 @@ public class MornyCommands { register( new ON(), new Hello(), /* new {@link HelloOnStart}, */ - new MornyInfoOnHello(), - new GetUsernameAndId(), - new EventHack(), - new Nbnhhsh(), - new Ip186Query.Ip(), - new Ip186Query.Whois(), - new Encryptor(), + MornyInformation$.MODULE$, + GetUsernameAndId$.MODULE$, + EventHack$.MODULE$, + Nbnhhsh$.MODULE$, + IP186Query.IP$.MODULE$, + IP186Query.Whois$.MODULE$, + Encryptor$.MODULE$, new SaveData(), - new MornyInformation(), + MornyInfoOnHello$.MODULE$, new Version(), new MornyRuntime(), new Jrrp(), @@ -72,21 +72,21 @@ public class MornyCommands { // 特殊的命令 register( - new Testing(), - new DirectMsgClear() + Testing$.MODULE$, + DirectMsgClear$.MODULE$ ); // 统一注册这些奇怪的东西&.& register( - new 私わね(), - new 喵呜.Progynova() + 私わね$.MODULE$, + 喵呜.Progynova$.MODULE$ ); // special: 注册出于兼容使用的特别 event 的数据 OnUniMeowTrigger.register( - new 喵呜.抱抱(), - new 喵呜.揉揉(), - new 喵呜.蹭蹭(), - new 喵呜.贴贴() + 喵呜.抱抱$.MODULE$, + 喵呜.揉揉$.MODULE$, + 喵呜.蹭蹭$.MODULE$, + 喵呜.贴贴$.MODULE$ ); } diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/command/Roll.java b/src/main/old/cc/sukazyo/cono/morny/bot/command/Roll.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/bot/command/Roll.java rename to src/main/old/cc/sukazyo/cono/morny/bot/command/Roll.java diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/command/package-info.java b/src/main/old/cc/sukazyo/cono/morny/bot/command/package-info.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/bot/command/package-info.java rename to src/main/old/cc/sukazyo/cono/morny/bot/command/package-info.java diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/event/EventListeners.java b/src/main/old/cc/sukazyo/cono/morny/bot/event/EventListeners.java similarity index 79% rename from src/main/java/cc/sukazyo/cono/morny/bot/event/EventListeners.java rename to src/main/old/cc/sukazyo/cono/morny/bot/event/EventListeners.java index 76c9256..f60095e 100644 --- a/src/main/java/cc/sukazyo/cono/morny/bot/event/EventListeners.java +++ b/src/main/old/cc/sukazyo/cono/morny/bot/event/EventListeners.java @@ -1,18 +1,15 @@ 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 OnUserSlashAction USER_SLASH_ACTION = new OnUserSlashAction(); public static final OnUpdateTimestampOffsetLock UPDATE_TIMESTAMP_OFFSET_LOCK = new OnUpdateTimestampOffsetLock(); - public static final OnInlineQueries INLINE_QUERY = new OnInlineQueries(); - public static final OnCallMe CALL_ME = new OnCallMe(); public static final OnEventHackHandle EVENT_HACK_HANDLE = new OnEventHackHandle(); // static final OnKuohuanhuanNeedSleep KUOHUANHUAN_NEED_SLEEP = new OnKuohuanhuanNeedSleep(); - public static final OnUserRandoms USER_RANDOMS = new OnUserRandoms(); 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(); @@ -28,11 +25,11 @@ public class EventListeners { COMMANDS_LISTENER, UNI_MEOW_TRIGGER, RANDOMLY_TRIGGERED, - USER_RANDOMS, + OnUserRandom$.MODULE$, QUESTION_MARK_REPLY, - USER_SLASH_ACTION, - INLINE_QUERY, - CALL_ME, + OnUserSlashAction$.MODULE$, + OnInlineQuery$.MODULE$, + OnCallMe$.MODULE$, CALL_MSG_SEND, MEDICATION_NOTIFY_APPLY, EVENT_HACK_HANDLE diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/event/OnActivityRecord.java b/src/main/old/cc/sukazyo/cono/morny/bot/event/OnActivityRecord.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/bot/event/OnActivityRecord.java rename to src/main/old/cc/sukazyo/cono/morny/bot/event/OnActivityRecord.java diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/event/OnCallMsgSend.java b/src/main/old/cc/sukazyo/cono/morny/bot/event/OnCallMsgSend.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/bot/event/OnCallMsgSend.java rename to src/main/old/cc/sukazyo/cono/morny/bot/event/OnCallMsgSend.java diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/event/OnEventHackHandle.java b/src/main/old/cc/sukazyo/cono/morny/bot/event/OnEventHackHandle.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/bot/event/OnEventHackHandle.java rename to src/main/old/cc/sukazyo/cono/morny/bot/event/OnEventHackHandle.java diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/event/OnKuohuanhuanNeedSleep.java b/src/main/old/cc/sukazyo/cono/morny/bot/event/OnKuohuanhuanNeedSleep.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/bot/event/OnKuohuanhuanNeedSleep.java rename to src/main/old/cc/sukazyo/cono/morny/bot/event/OnKuohuanhuanNeedSleep.java diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/event/OnMedicationNotifyApply.java b/src/main/old/cc/sukazyo/cono/morny/bot/event/OnMedicationNotifyApply.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/bot/event/OnMedicationNotifyApply.java rename to src/main/old/cc/sukazyo/cono/morny/bot/event/OnMedicationNotifyApply.java diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/event/OnQuestionMarkReply.java b/src/main/old/cc/sukazyo/cono/morny/bot/event/OnQuestionMarkReply.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/bot/event/OnQuestionMarkReply.java rename to src/main/old/cc/sukazyo/cono/morny/bot/event/OnQuestionMarkReply.java diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/event/OnRandomlyTriggered.java b/src/main/old/cc/sukazyo/cono/morny/bot/event/OnRandomlyTriggered.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/bot/event/OnRandomlyTriggered.java rename to src/main/old/cc/sukazyo/cono/morny/bot/event/OnRandomlyTriggered.java diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/event/OnTelegramCommand.java b/src/main/old/cc/sukazyo/cono/morny/bot/event/OnTelegramCommand.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/bot/event/OnTelegramCommand.java rename to src/main/old/cc/sukazyo/cono/morny/bot/event/OnTelegramCommand.java diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/event/OnUniMeowTrigger.java b/src/main/old/cc/sukazyo/cono/morny/bot/event/OnUniMeowTrigger.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/bot/event/OnUniMeowTrigger.java rename to src/main/old/cc/sukazyo/cono/morny/bot/event/OnUniMeowTrigger.java diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/event/OnUpdateTimestampOffsetLock.java b/src/main/old/cc/sukazyo/cono/morny/bot/event/OnUpdateTimestampOffsetLock.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/bot/event/OnUpdateTimestampOffsetLock.java rename to src/main/old/cc/sukazyo/cono/morny/bot/event/OnUpdateTimestampOffsetLock.java diff --git a/src/main/java/cc/sukazyo/cono/morny/daemon/MedicationTimer.java b/src/main/old/cc/sukazyo/cono/morny/daemon/MedicationTimer.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/daemon/MedicationTimer.java rename to src/main/old/cc/sukazyo/cono/morny/daemon/MedicationTimer.java diff --git a/src/main/java/cc/sukazyo/cono/morny/daemon/MornyDaemons.java b/src/main/old/cc/sukazyo/cono/morny/daemon/MornyDaemons.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/daemon/MornyDaemons.java rename to src/main/old/cc/sukazyo/cono/morny/daemon/MornyDaemons.java diff --git a/src/main/java/cc/sukazyo/cono/morny/daemon/MornyReport.java b/src/main/old/cc/sukazyo/cono/morny/daemon/MornyReport.java similarity index 99% rename from src/main/java/cc/sukazyo/cono/morny/daemon/MornyReport.java rename to src/main/old/cc/sukazyo/cono/morny/daemon/MornyReport.java index 11a646c..9a81a5e 100644 --- a/src/main/java/cc/sukazyo/cono/morny/daemon/MornyReport.java +++ b/src/main/old/cc/sukazyo/cono/morny/daemon/MornyReport.java @@ -88,7 +88,7 @@ public class MornyReport { as config fields: %s """, - MornyInformation.getVersionAllFullTagHtml(), + MornyInformation.getVersionAllFullTagHTML(), MornyCoeur.getUsername(), sectionConfigFields(MornyCoeur.config()) ) diff --git a/src/main/java/cc/sukazyo/cono/morny/daemon/TrackerDataManager.java b/src/main/old/cc/sukazyo/cono/morny/daemon/TrackerDataManager.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/daemon/TrackerDataManager.java rename to src/main/old/cc/sukazyo/cono/morny/daemon/TrackerDataManager.java diff --git a/src/main/java/cc/sukazyo/cono/morny/data/MornyJrrp.java b/src/main/old/cc/sukazyo/cono/morny/data/MornyJrrp.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/data/MornyJrrp.java rename to src/main/old/cc/sukazyo/cono/morny/data/MornyJrrp.java diff --git a/src/main/java/cc/sukazyo/cono/morny/data/NbnhhshQuery.java b/src/main/old/cc/sukazyo/cono/morny/data/NbnhhshQuery.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/data/NbnhhshQuery.java rename to src/main/old/cc/sukazyo/cono/morny/data/NbnhhshQuery.java diff --git a/src/main/java/cc/sukazyo/cono/morny/data/TelegramImages.java b/src/main/old/cc/sukazyo/cono/morny/data/TelegramImages.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/data/TelegramImages.java rename to src/main/old/cc/sukazyo/cono/morny/data/TelegramImages.java diff --git a/src/main/java/cc/sukazyo/cono/morny/data/TelegramStickers.java b/src/main/old/cc/sukazyo/cono/morny/data/TelegramStickers.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/data/TelegramStickers.java rename to src/main/old/cc/sukazyo/cono/morny/data/TelegramStickers.java diff --git a/src/main/java/cc/sukazyo/cono/morny/internal/BuildConfigField.java b/src/main/old/cc/sukazyo/cono/morny/internal/BuildConfigField.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/internal/BuildConfigField.java rename to src/main/old/cc/sukazyo/cono/morny/internal/BuildConfigField.java diff --git a/src/main/java/cc/sukazyo/cono/morny/util/BiliTool.java b/src/main/old/cc/sukazyo/cono/morny/util/BiliTool.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/util/BiliTool.java rename to src/main/old/cc/sukazyo/cono/morny/util/BiliTool.java diff --git a/src/main/java/cc/sukazyo/cono/morny/util/CommonConvert.java b/src/main/old/cc/sukazyo/cono/morny/util/CommonConvert.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/util/CommonConvert.java rename to src/main/old/cc/sukazyo/cono/morny/util/CommonConvert.java diff --git a/src/main/java/cc/sukazyo/cono/morny/util/CommonEncrypt.java b/src/main/old/cc/sukazyo/cono/morny/util/CommonEncrypt.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/util/CommonEncrypt.java rename to src/main/old/cc/sukazyo/cono/morny/util/CommonEncrypt.java diff --git a/src/main/java/cc/sukazyo/cono/morny/util/CommonFormat.java b/src/main/old/cc/sukazyo/cono/morny/util/CommonFormat.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/util/CommonFormat.java rename to src/main/old/cc/sukazyo/cono/morny/util/CommonFormat.java diff --git a/src/main/java/cc/sukazyo/cono/morny/util/CommonRandom.java b/src/main/old/cc/sukazyo/cono/morny/util/CommonRandom.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/util/CommonRandom.java rename to src/main/old/cc/sukazyo/cono/morny/util/CommonRandom.java diff --git a/src/main/java/cc/sukazyo/cono/morny/util/FileUtils.java b/src/main/old/cc/sukazyo/cono/morny/util/FileUtils.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/util/FileUtils.java rename to src/main/old/cc/sukazyo/cono/morny/util/FileUtils.java diff --git a/src/main/java/cc/sukazyo/cono/morny/util/OkHttpPublic.java b/src/main/old/cc/sukazyo/cono/morny/util/OkHttpPublic.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/util/OkHttpPublic.java rename to src/main/old/cc/sukazyo/cono/morny/util/OkHttpPublic.java diff --git a/src/main/java/cc/sukazyo/cono/morny/util/UniversalCommand.java b/src/main/old/cc/sukazyo/cono/morny/util/UniversalCommand.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/util/UniversalCommand.java rename to src/main/old/cc/sukazyo/cono/morny/util/UniversalCommand.java diff --git a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/ExtraAction.java b/src/main/old/cc/sukazyo/cono/morny/util/tgapi/ExtraAction.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/util/tgapi/ExtraAction.java rename to src/main/old/cc/sukazyo/cono/morny/util/tgapi/ExtraAction.java diff --git a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/InputCommand.java b/src/main/old/cc/sukazyo/cono/morny/util/tgapi/InputCommand.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/util/tgapi/InputCommand.java rename to src/main/old/cc/sukazyo/cono/morny/util/tgapi/InputCommand.java diff --git a/src/main/old/cc/sukazyo/cono/morny/util/tgapi/Standardize.java b/src/main/old/cc/sukazyo/cono/morny/util/tgapi/Standardize.java new file mode 100644 index 0000000..ae3efa3 --- /dev/null +++ b/src/main/old/cc/sukazyo/cono/morny/util/tgapi/Standardize.java @@ -0,0 +1,7 @@ +package cc.sukazyo.cono.morny.util.tgapi; + +public class Standardize { + + public static final int CHANNEL_SPEAKER_MAGIC_ID = 136817688; + +} diff --git a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/event/EventRuntimeException.java b/src/main/old/cc/sukazyo/cono/morny/util/tgapi/event/EventRuntimeException.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/util/tgapi/event/EventRuntimeException.java rename to src/main/old/cc/sukazyo/cono/morny/util/tgapi/event/EventRuntimeException.java diff --git a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/MsgEscape.java b/src/main/old/cc/sukazyo/cono/morny/util/tgapi/formatting/MsgEscape.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/MsgEscape.java rename to src/main/old/cc/sukazyo/cono/morny/util/tgapi/formatting/MsgEscape.java diff --git a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/NamedUtils.java b/src/main/old/cc/sukazyo/cono/morny/util/tgapi/formatting/NamedUtils.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/NamedUtils.java rename to src/main/old/cc/sukazyo/cono/morny/util/tgapi/formatting/NamedUtils.java diff --git a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToString.java b/src/main/old/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToString.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToString.java rename to src/main/old/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToString.java diff --git a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromChat.java b/src/main/old/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromChat.java similarity index 92% rename from src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromChat.java rename to src/main/old/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromChat.java index 8671056..46045f0 100644 --- a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromChat.java +++ b/src/main/old/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromChat.java @@ -1,6 +1,7 @@ package cc.sukazyo.cono.morny.util.tgapi.formatting; import com.pengrad.telegrambot.model.Chat; +import com.pengrad.telegrambot.model.Message; public class TGToStringFromChat { diff --git a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromMessage.java b/src/main/old/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromMessage.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromMessage.java rename to src/main/old/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromMessage.java diff --git a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromUser.java b/src/main/old/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromUser.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromUser.java rename to src/main/old/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromUser.java diff --git a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramUserInformation.java b/src/main/old/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramUserInformation.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramUserInformation.java rename to src/main/old/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramUserInformation.java diff --git a/src/main/scala/cc/sukazyo/cono/morny/ServerMain.scala b/src/main/scala/cc/sukazyo/cono/morny/ServerMain.scala new file mode 100644 index 0000000..91907ae --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/ServerMain.scala @@ -0,0 +1,156 @@ +package cc.sukazyo.cono.morny + +import cc.sukazyo.cono.morny.Log.logger +import cc.sukazyo.cono.morny.MornyConfig.CheckFailure +import cc.sukazyo.cono.morny.util.CommonFormat + +import java.time.ZoneOffset +import scala.collection.mutable.ArrayBuffer +import scala.language.postfixOps + +object ServerMain { + + private val THREAD_MORNY_INIT: String = "morny-init" + + val systemStartupTime: Long = System.currentTimeMillis() + + def main (args: Array[String]): Unit = { + + val config = new MornyConfig.Prototype() + var mode_echoVersion = false + var mode_echoHello = false + var showHello = true + + config.eventOutdatedTimestamp = systemStartupTime + + val unknownArgs = ArrayBuffer[String]() + + var i = 0 + while (i < args.length) { + args(i) match { + + case "-d" | "--dbg" | "--debug" => Log.debug(true) + + case "--no-hello" | "-hf" | "--quiet" | "-q" => showHello = false + case "--only-hello" | "-ho" | "-o" | "-hi" => mode_echoHello = true + case "--version" | "-v" => mode_echoVersion = true + + case "--outdated-block" | "-ob" => config.eventIgnoreOutdated = true + + case "--api" | "-a" => i+=1 ; config.telegramBotApiServer = args(i) + case "--api-files" | "files-api" | "-af" => i+=1; config.telegramBotApiServer4File = args(i) + + case "--token" | "-t" => i+=1 ; config.telegramBotKey = args(i) + case "--username" | "-u" => i+=1 ; config.telegramBotUsername = args(i) + + case "--master" | "-mm" => i+=1 ; config.trustedMaster = args(i)toLong + case "--trusted-chat" | "-trs" => i+=1 ; config.trustedChat = args(i)toLong + case "--report-to" => i+=1; config.reportToChat = args(i)toLong + + case "--trusted-reader-dinner" | "-trsd" => i+=1 ; config.dinnerTrustedReaders add (args(i)toLong) + case "--dinner-chat" | "-chd" => i+=1 ; config.dinnerChatId = args(i)toLong + + case "--medication-notify-chat" | "-medc" => i+=1 ; config.medicationNotifyToChat = args(i)toLong + case "--medication-notify-timezone" | "-medtz" => + i+=1 + config.medicationTimerUseTimezone = ZoneOffset.ofHours(args(i)toInt) + case "--medication-notify-times" | "-medt" => + i+=1 + for (u <- args(i) split ",") { + config.medicationNotifyAt add (u toInt) + } + + case "--auto-cmd-list" | "-ca" => config.commandLoginRefresh = true + case "--auto-cmd-remove" | "-cr" => config.commandLogoutClear = true + case "--auto-cmd" | "-cmd" | "-c" => + config.commandLoginRefresh = true + config.commandLogoutClear = true + + case _ => unknownArgs append args(i) + + } + i+=1 + } + + /// Setup launch params from ENVIRONMENT + var propToken: String = null + var propTokenKey: String = null + for (iKey <- MornyConfig.PROP_TOKEN_KEY) { + if ((System getenv iKey) != null) { + propToken = System getenv iKey + propTokenKey = iKey + } + } + + /// + /// Output startup message + /// process startup params - like startup mode + /// + + if (showHello) logger info MornyAbout.MORNY_PREVIEW_IMAGE_ASCII + if (mode_echoHello) return; + + if (unknownArgs.nonEmpty) logger warn + s"""Can't understand arg to some meaning + | ${unknownArgs mkString "\n "}""" + .stripMargin + + if (Log debug) + logger warn + """Debug log output enabled. + | It may lower your performance, make sure that you are not in production environment.""" + .stripMargin + + if (mode_echoVersion) { + + logger info + s"""Morny Cono Version + |- version : + | Morny ${MornySystem.CODENAME toUpperCase} + | ${MornySystem.VERSION_BASE}${if (MornySystem.isUseDelta) "-δ"+MornySystem.VERSION_DELTA else ""} + |- md5hash : + | ${MornySystem.getJarMd5} + |- gitstat : + |${ if (MornySystem.isGitBuild) { + s""" on commit ${if (MornySystem.isCleanBuild) "- clean-build" else "<δ/non-clean-build>"} + | ${BuildConfig.COMMIT}""" + .stripMargin + } else " "} + |- buildtd : + | ${BuildConfig.CODE_TIMESTAMP} + | ${CommonFormat.formatDate(BuildConfig.CODE_TIMESTAMP, 0)} [UTC]""" + .stripMargin + return + + } + + logger info + s"""ServerMain.java Loaded >>> + |- version ${MornySystem.VERSION_FULL} + |- Morny ${MornySystem.CODENAME toUpperCase} + |- <${MornySystem.getJarMd5}> [${BuildConfig.CODE_TIMESTAMP}]""".stripMargin + + /// + /// Check Coeur arguments + /// finally start Coeur Program + /// + + if (propToken != null) { + config.telegramBotKey = propToken + logger info s"Parameter set by EnvVar $$$propTokenKey" + } + + Thread.currentThread setName THREAD_MORNY_INIT + + try + MornyCoeur.init(new MornyConfig(config)) + catch { + case _: CheckFailure.NullTelegramBotKey => + logger.info("Parameter required has no value:\n --token.") + case e: CheckFailure => + logger.error("Unknown failure occurred while starting ServerMain!:") + e.printStackTrace(System.out) + } + } + +} 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 new file mode 100644 index 0000000..e3e1761 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/DirectMsgClear.scala @@ -0,0 +1,54 @@ +package cc.sukazyo.cono.morny.bot.command + +import cc.sukazyo.cono.morny.Log.logger +import cc.sukazyo.cono.morny.MornyCoeur +import cc.sukazyo.cono.morny.data.TelegramStickers +import cc.sukazyo.cono.morny.util.tgapi.InputCommand +import com.pengrad.telegrambot.model.{Chat, Update} +import com.pengrad.telegrambot.request.{DeleteMessage, GetChatMember, SendSticker} + +import scala.language.postfixOps + +object DirectMsgClear extends ISimpleCommand { + + override def getName: String = "r" + override def getAliases: Array[String] = null + + override def execute (command: InputCommand, event: Update): Unit = { + + logger debug "executing command /r" + if (event.message.replyToMessage == null) return; + logger trace "message is a reply" + if (event.message.replyToMessage.from.id != MornyCoeur.getUserid) return; + logger trace "message replied is from me" + if (System.currentTimeMillis/1000 - event.message.replyToMessage.date > 48*60*60) return; + logger trace "message is not outdated(48 hrs ago)" + + val isTrusted = MornyCoeur.trustedInstance isTrusted event.message.from.id + def _isReplyTrusted: Boolean = + if (event.message.replyToMessage.replyToMessage == null) false + else if (event.message.replyToMessage.replyToMessage.from.id == event.message.from.id) true + else false + + if (isTrusted || _isReplyTrusted) { + + MornyCoeur.extra exec DeleteMessage( + event.message.chat.id, event.message.replyToMessage.messageId + ) + + def _isPrivate: Boolean = event.message.chat.`type` == Chat.Type.Private + def _isPermission: Boolean = + (MornyCoeur.extra exec GetChatMember(event.message.chat.id, event.message.from.id)) + .chatMember.canDeleteMessages + if (_isPrivate || _isPermission) { + MornyCoeur.extra exec DeleteMessage(event.message.chat.id, event.message.messageId) + } + + } else MornyCoeur.extra exec SendSticker( + event.message.chat.id, + TelegramStickers ID_403 + ).replyToMessageId(event.message.messageId) + + } + +} 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 new file mode 100644 index 0000000..77be888 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/Encryptor.scala @@ -0,0 +1,178 @@ +package cc.sukazyo.cono.morny.bot.command + +import cc.sukazyo.cono.morny.Log.logger +import cc.sukazyo.cono.morny.MornyCoeur +import cc.sukazyo.cono.morny.daemon.MornyReport +import cc.sukazyo.cono.morny.data.TelegramStickers +import cc.sukazyo.cono.morny.util.CommonConvert.byteArrayToHex +import cc.sukazyo.cono.morny.util.CommonEncrypt +import cc.sukazyo.cono.morny.util.CommonEncrypt.* +import cc.sukazyo.cono.morny.util.tgapi.InputCommand +import com.pengrad.telegrambot.model.{PhotoSize, Update} +import com.pengrad.telegrambot.model.request.ParseMode +import com.pengrad.telegrambot.request.{GetFile, SendDocument, SendMessage, SendSticker} + +import java.io.IOException +import java.util.Base64 +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 def execute (command: InputCommand, event: Update): Unit = { + + val args = command.getArgs + + if ((args isEmpty) || ((args(0) equals "l") && (args.length == 1))) + echoHelp(event.message.chat.id, event.message.messageId) + return + + def _is_mod_u(arg: String): Boolean = + if (arg equalsIgnoreCase "uppercase") return true + if (arg equalsIgnoreCase "u") return true + if (arg equalsIgnoreCase "upper") return true + false + val mod_uppercase = if (args.length > 1) { + if (args.length < 3 && _is_mod_u(args(1))) true + else + MornyCoeur.extra exec SendSticker( + event.message.chat.id, + TelegramStickers ID_404 + ).replyToMessageId(event.message.messageId) + return + } else false + + trait XEncryptable { val asByteArray: Array[Byte] } + case class XFile (data: Array[Byte], name: String) extends XEncryptable { + val asByteArray: Array[Byte] = data + } + case class XText (data: String) extends XEncryptable { + val asByteArray: Array[Byte] = data getBytes CommonEncrypt.ENCRYPT_STANDARD_CHARSET + } + val input: XEncryptable = + val _r = event.message.replyToMessage + if ((_r ne null) && (_r.document ne null)) { + try {XFile( + MornyCoeur.getAccount getFileContent (MornyCoeur.extra exec GetFile(_r.document.fileId)).file, + _r.document.fileName + )} catch case e: IOException => + logger warn s"NetworkRequest error: TelegramFileAPI:\n\t${e.getMessage}" + MornyReport.exception(e, "NetworkRequest error: TelegramFileAPI") + return + } else if ((_r ne null) && (_r.photo ne null)) { + try { + var _photo_origin: PhotoSize = null + var _photo_size: Long = 0 + for (size <- _r.photo) + val _size = (size.width longValue)*size.height + if (_photo_size < _size) + _photo_origin = size + _photo_size = _size + if (_photo_origin eq null) throw IllegalArgumentException("no photo from api.") + XFile( + MornyCoeur.getAccount getFileContent (MornyCoeur.extra exec GetFile(_photo_origin.fileId)).file, + s"photo${byteArrayToHex(hashMd5(System.currentTimeMillis toString)) substring 32-12 toUpperCase}.png" + ) + } catch + case e: IOException => + logger warn s"NetworkRequest error: TelegramFileAPI:\n\t${e.getMessage}" + MornyReport.exception(e, "NetworkRequest error: TelegramFileAPI") + return + case e: IllegalArgumentException => + logger warn s"FileProcess error: PhotoSize:\n\t${e.getMessage}" + MornyReport.exception(e, "FileProcess error: PhotoSize") + return + } else if ((_r ne null) && (_r.text ne null)) { + XText(_r.text) + } else { + MornyCoeur.extra exec SendMessage( + event.message.chat.id, + "null" + ).parseMode(ParseMode HTML).replyToMessageId(event.message.messageId) + return + } + + + trait EXTextLike { val text: String } + case class EXFile (result: Array[Byte], resultName: String) + case class EXText (result: String) extends EXTextLike { override val text:String = result } + case class EXHash (result: String) extends EXTextLike { override val text:String = result } + def genResult_encrypt (source: XEncryptable, processor: Array[Byte]=>Array[Byte], filenameProcessor: String=>String): EXFile|EXText = { + source match + case x_file: XFile => EXFile(processor(x_file asByteArray), filenameProcessor(x_file.name)) + case x: XText => EXText(String(processor(x asByteArray), ENCRYPT_STANDARD_CHARSET)) + } + def genResult_hash (source: XEncryptable, processor: Array[Byte]=>Array[Byte]): EXHash = + val hashed = byteArrayToHex(processor(source asByteArray)) + EXHash(if mod_uppercase then hashed toUpperCase else hashed) + val result: EXHash|EXFile|EXText = args(0) match + case "base64" | "b64" | "base64url" | "base64u" | "b64u" => + val _tool_b64 = + if args(0) contains "u" then Base64.getUrlEncoder + else Base64.getEncoder + genResult_encrypt( + input, + _tool_b64.encode, + n => n+".b64.txt" + ) + case "base64decode" | "base64d" | "b64d" | "base64url-decode" | "base64ud" | "b64ud" => + val _tool_b64d = + if args(0) contains "u" then Base64.getUrlDecoder + else Base64.getDecoder + try { genResult_encrypt( + input, + _tool_b64d.decode, + CommonEncrypt.base64FilenameLint + ) } catch case _: IllegalArgumentException => + MornyCoeur.extra exec SendSticker( + event.message.chat.id, + TelegramStickers ID_404 // todo: is here better erro notify? + ).replyToMessageId(event.message.messageId) + return + case "md5" => genResult_hash(input, hashMd5) + case "sha1" => genResult_hash(input, hashSha1) + case "sha256" => genResult_hash(input, hashSha256) + case "sha512" => genResult_hash(input, hashSha512) + case _ => + MornyCoeur.extra exec SendSticker( + event.message.chat.id, + TelegramStickers ID_404 + ).replyToMessageId(event.message.messageId) + return; + + result match + case _file: EXFile => + MornyCoeur.extra exec SendDocument( + event.message.chat.id, + _file.result + ).fileName(_file.resultName).replyToMessageId(event.message.messageId) + case _text: EXTextLike => + import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h + MornyCoeur.extra exec SendMessage( + event.message.chat.id, + s"
${h(_text.text)}
" + ).parseMode(ParseMode HTML).replyToMessageId(event.message.messageId) + + } + + private def echoHelp(chat: Long, replyTo: Int): Unit = + MornyCoeur.extra exec SendMessage( + chat, + s"""base64, b64 + |base64url, base64u, b64u + |base64decode, base64d, b64d + |base64url-decode, base64ud, b64ud + |sha1 + |sha256 + |sha512 + |md5 + |--- + |uppercase, upper, u (sha1/sha256/sha512/md5 only)""" + .stripMargin + ).replyToMessageId(replyTo).parseMode(ParseMode HTML) + +} 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 new file mode 100644 index 0000000..a4fddb0 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/EventHack.scala @@ -0,0 +1,56 @@ +package cc.sukazyo.cono.morny.bot.command +import cc.sukazyo.cono.morny.MornyCoeur +import cc.sukazyo.cono.morny.bot.event.OnEventHackHandle +import cc.sukazyo.cono.morny.util.tgapi.InputCommand +import com.pengrad.telegrambot.model.Update +import OnEventHackHandle.{HackType, registerHack} +import cc.sukazyo.cono.morny.data.TelegramStickers +import com.pengrad.telegrambot.request.SendSticker + +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 def execute (command: InputCommand, event: Update): Unit = { + + val x_mode = if (command.hasArgs) command.getArgs()(0) else "" + + def done_ok = + MornyCoeur.extra exec SendSticker( + event.message.chat.id, + TelegramStickers ID_WAITING + ).replyToMessageId(event.message.messageId) + def done_forbiddenForAny = + MornyCoeur.extra exec SendSticker( + event.message.chat.id, + TelegramStickers ID_403 + ).replyToMessageId(event.message.messageId) + + def doRegister (t: HackType): Unit = + registerHack( + event.message.messageId longValue, + event.message.from.id, + event.message.chat.id, + t + ) + x_mode match + case "any" => + if (MornyCoeur.trustedInstance isTrusted event.message.from.id) + doRegister(HackType ANY) + done_ok + else done_forbiddenForAny + case "group" => + doRegister(HackType GROUP) + done_ok + case _ => + doRegister(HackType USER) + done_ok + + } + +} 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 new file mode 100644 index 0000000..3f03650 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/GetUsernameAndId.scala @@ -0,0 +1,66 @@ +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 com.pengrad.telegrambot.model.Update +import com.pengrad.telegrambot.model.request.ParseMode +import com.pengrad.telegrambot.request.{GetChatMember, SendMessage} + +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 def execute (command: InputCommand, event: Update): Unit = { + + val args = command.getArgs + + if (args.length > 1) + MornyCoeur.extra exec SendMessage( + event.message.chat.id, + "[Unavailable] Too much arguments." + ).replyToMessageId(event.message.messageId) + return + + val userId: Long = + if (args nonEmpty) { + try args(0) toLong + catch case e: NumberFormatException => + MornyCoeur.extra exec SendMessage( + event.message.chat.id, + s"[Unavailable] ${e.getMessage}" + ).replyToMessageId(event.message.messageId) + return + } else if (event.message.replyToMessage eq null) event.message.from.id + else event.message.replyToMessage.from.id + + val response = MornyCoeur.getAccount execute GetChatMember(event.message.chat.id, userId) + + if (response.chatMember eq null) + MornyCoeur.extra exec SendMessage( + event.message.chat.id, + "[Unavailable] user not found." + ).replyToMessageId(event.message.messageId) + return + + val user = response.chatMember.user + + if (user.id eq Standardize.CHANNEL_SPEAKER_MAGIC_ID) + MornyCoeur.extra exec SendMessage( + event.message.chat.id, + "$__channel_identify" + ).replyToMessageId(event.message.messageId) + return; + + MornyCoeur.extra exec SendMessage( + event.message.chat.id, + TelegramUserInformation informationOutputHTML user + ).replyToMessageId(event.message.messageId()).parseMode(ParseMode HTML) + + } + +} 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 new file mode 100644 index 0000000..a901580 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/IP186Query.scala @@ -0,0 +1,77 @@ +package cc.sukazyo.cono.morny.bot.command + +import cc.sukazyo.cono.morny.MornyCoeur +import cc.sukazyo.cono.morny.data.ip186.IP186QueryHandler +import cc.sukazyo.cono.morny.util.tgapi.InputCommand +import com.pengrad.telegrambot.model.Update +import com.pengrad.telegrambot.model.request.ParseMode +import com.pengrad.telegrambot.request.SendMessage + +import scala.language.postfixOps + +object IP186Query { + + private enum Subs (val cmd: String): + case IP extends Subs("ip") + 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) + 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) + + private def query (event: Update, command: InputCommand): Unit = { + + val target: String|Null = + if (command.getArgs isEmpty) + if event.message.replyToMessage eq null then null else event.message.replyToMessage.text + else if (command.getArgs.length > 1) + MornyCoeur.extra exec SendMessage( + event.message.chat.id, + "[Unavailable] Too much arguments." + ).replyToMessageId(event.message.messageId) + return + else command.getArgs()(0) + + if (target eq null) + MornyCoeur.extra exec new SendMessage( + event.message.chat.id, + "[Unavailable] No ip defined." + ).replyToMessageId(event.message.messageId) + return; + + try { + + val response = command.getCommand match + case Subs.IP.cmd => IP186QueryHandler.query_ip(target) + case Subs.WHOIS.cmd => IP186QueryHandler.query_whoisPretty(target) + case _ => throw IllegalArgumentException(s"Unknown 186-IP query method ${command.getCommand}") + + import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h + MornyCoeur.extra exec SendMessage( + event.message.chat.id, + s"""${h(response.url)} + |${h(response.body)}""" + .stripMargin + ).parseMode(ParseMode HTML).replyToMessageId(event.message.messageId) + + } catch case e: Exception => + import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h + MornyCoeur.extra().exec(new SendMessage( + event.message().chat().id(), + s"""[Exception] in query: + |${h(e.getMessage)}""" + .stripMargin + ).parseMode(ParseMode.HTML).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/MornyInfoOnHello.scala new file mode 100644 index 0000000..2df1ba5 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyInfoOnHello.scala @@ -0,0 +1,35 @@ +package cc.sukazyo.cono.morny.bot.command + +import cc.sukazyo.cono.morny.MornyCoeur +import cc.sukazyo.cono.morny.util.tgapi.InputCommand +import com.pengrad.telegrambot.model.Update +import com.pengrad.telegrambot.model.request.ParseMode +import com.pengrad.telegrambot.request.SendPhoto + +import scala.language.postfixOps + +object MornyInfoOnHello extends ISimpleCommand { + + override def getName: String = "start" + override def getAliases: Array[String] = Array() + + override def execute (command: InputCommand, event: Update): Unit = { + + MornyCoeur.extra exec new SendPhoto( + event.message.chat.id, + MornyInformation.getAboutPic + ).caption( + s"""欢迎使用 Morny Cono来自安妮的侍从小鼠。 + |Morny 具有各种各样的功能。 + | + |———————————————— + |${MornyInformation.getMornyAboutLinksHTML} + |———————————————— + | + |(你可以随时通过 /info 重新获得这些信息)""" + .stripMargin + ).parseMode(ParseMode HTML) + + } + +} 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 new file mode 100644 index 0000000..e81a9fb --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyInformation.scala @@ -0,0 +1,167 @@ +package cc.sukazyo.cono.morny.bot.command + +import cc.sukazyo.cono.morny.data.{TelegramImages, TelegramStickers} +import cc.sukazyo.cono.morny.util.CommonFormat.{formatDate, formatDuration} +import cc.sukazyo.cono.morny.util.tgapi.InputCommand +import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h +import cc.sukazyo.cono.morny.{BuildConfig, MornyAbout, MornyCoeur, MornySystem} +import com.pengrad.telegrambot.model.Update +import com.pengrad.telegrambot.model.request.ParseMode +import com.pengrad.telegrambot.request.{SendMessage, SendPhoto, SendSticker} + +import java.lang.System +import java.net.InetAddress +import java.rmi.UnknownHostException +import scala.language.postfixOps + +object MornyInformation extends ITelegramCommand { + + private case object Subs { + val STICKERS = "stickers" + val RUNTIME = "runtime" + val VERSION = "version" + 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 def execute (command: InputCommand, event: Update): Unit = { + + if (!command.hasArgs) { + echoInfo(event.message.chat.id, event.message.messageId) + return + } + + 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) + } + + } + + def getVersionGitTagHTML: String = { + if (!MornySystem.isGitBuild) return "" + val g = StringBuilder() + val cm = BuildConfig.COMMIT substring(0, 8) + val cp = MornySystem.currentCodePath + if (cp == null) g++= s"$cm" + else g++= s"$cm" + if (!MornySystem.isCleanBuild) g++= ".δ" + g toString + } + + def getVersionAllFullTagHTML: String = { + val v = StringBuilder() + v ++= s"${MornySystem VERSION_BASE}" + if (MornySystem isUseDelta) v++=s"-δ${MornySystem VERSION_DELTA}" + if (MornySystem isGitBuild) v++="+"++=getVersionGitTagHTML + v ++= s"*${MornySystem.CODENAME toUpperCase}" + v toString + } + + def getRuntimeHostname: String|Null = { + try InetAddress.getLocalHost.getHostName + catch case _:UnknownHostException => null + } + + def getAboutPic: Array[Byte] = TelegramImages.IMG_ABOUT get + + def getMornyAboutLinksHTML: String = + s"""source code | backup + |反馈 / issue tracker + |使用说明书 / user guide & docs""" + .stripMargin + + private def echoInfo (chatId: Long, replyTo: Int): Unit = { + MornyCoeur.extra exec new SendPhoto( + chatId, + getAboutPic + ).caption( + s"""Morny Cono + |来自安妮的侍从小鼠。 + |———————————————— + |$getMornyAboutLinksHTML""" + .stripMargin + ).parseMode(ParseMode HTML).replyToMessageId(replyTo) + } + + private def echoStickers (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.length == 1) sid = "" + else if (command.getArgs.length == 2) sid = command.getArgs()(1) + } else if (command.getArgs.length == 1) { + if ((command.getArgs()(0) startsWith s"${Subs.STICKERS}.") || (command.getArgs()(0) startsWith s"${Subs.STICKERS}#")) { + sid = command.getArgs()(0) substring Subs.STICKERS.length+1 + } + } + if (sid == null) echo404(event) + else echoStickers(sid, chat, replyTo) + } + + private def echoStickers (sid: String, send_chat: Long, send_replyTo: Int): Unit = { + if (sid isEmpty) TelegramStickers echoAllStickers(MornyCoeur.extra, send_chat, send_replyTo) + else TelegramStickers echoStickerByID(sid, MornyCoeur.extra, send_chat, send_replyTo) + } + + private[command] def echoVersion (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, + s"""version: + |- Morny ${h(MornySystem.CODENAME toUpperCase)} + |- ${h(MornySystem.VERSION_BASE)}$versionDeltaHTML${if (MornySystem.isGitBuild) "\n- " + versionGitHTML else ""} + |coeur md5_hash: + |- ${h(MornySystem.getJarMd5)} + |coding timestamp: + |- ${BuildConfig.CODE_TIMESTAMP} + |- ${h(formatDate(BuildConfig.CODE_TIMESTAMP, 0))} [UTC] + |""".stripMargin + ).replyToMessageId(event.message.messageId).parseMode(ParseMode HTML) + } + + private[command] def echoRuntime (event: Update): Unit = { + def sysprop (p: String): String = System.getProperty(p) + MornyCoeur.extra exec new SendMessage( + event.message.chat.id, + /* html */ + s"""system: + |- Morny ${h(if (getRuntimeHostname == null) "" else getRuntimeHostname)} + |- ${h(sysprop("os.name"))} ${h(sysprop("os.arch"))} ${h(sysprop("os.version"))} + |java runtime: + |- ${h(sysprop("java.vm.vendor"))}.${h(sysprop("java.vm.name"))} + |- ${h(sysprop("java.vm.version"))} + |vm memory: + |- ${Runtime.getRuntime.totalMemory/1024/1024} / ${Runtime.getRuntime.maxMemory/1024/1024} + |- ${Runtime.getRuntime.availableProcessors} cores + |coeur version: + |- $getVersionAllFullTagHTML + |- ${h(MornySystem.getJarMd5)} + |- ${h(formatDate(BuildConfig.CODE_TIMESTAMP, 0))} [UTC] + |- [${BuildConfig.CODE_TIMESTAMP}] + |continuous: + |- ${h(formatDuration(System.currentTimeMillis - MornyCoeur.coeurStartTimestamp))} + |- [${System.currentTimeMillis - MornyCoeur.coeurStartTimestamp}] + |- ${h(formatDate(MornyCoeur.coeurStartTimestamp, 0))} + |- [${MornyCoeur.coeurStartTimestamp}]""" + .stripMargin + ).parseMode(ParseMode HTML).replyToMessageId(event.message.messageId) + } + + private def echo404 (event: Update): Unit = + MornyCoeur.extra exec new SendSticker( + event.message.chat.id, + TelegramStickers ID_404 + ).replyToMessageId(event.message.messageId) + +} 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 new file mode 100644 index 0000000..5c7d799 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/Nbnhhsh.scala @@ -0,0 +1,85 @@ +package cc.sukazyo.cono.morny.bot.command + +import cc.sukazyo.cono.morny.MornyCoeur +import cc.sukazyo.cono.morny.data.{NbnhhshQuery, TelegramStickers} +import cc.sukazyo.cono.morny.util.tgapi.InputCommand +import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h +import com.pengrad.telegrambot.model.Update +import com.pengrad.telegrambot.model.request.ParseMode +import com.pengrad.telegrambot.request.{SendMessage, SendSticker} + +import java.io.IOException +import scala.language.postfixOps + +object Nbnhhsh extends ITelegramCommand { + + private val NBNHHSH_RESULT_HEAD_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 def execute (command: InputCommand, event: Update): Unit = { + + val queryTarget: String|Null = + import cc.sukazyo.cono.morny.util.CommonConvert.stringsConnecting + if (event.message.replyToMessage != null && event.message.replyToMessage.text != null) + event.message.replyToMessage.text + else if command hasArgs then + stringsConnecting(command.getArgs, " ", 0, command.getArgs.length-1) + else null + + if (queryTarget == null) + MornyCoeur.extra exec SendSticker( + event.message.chat.id, + TelegramStickers ID_404 + ).replyToMessageId(event.message.messageId) + return; + + try { + + val queryResp = NbnhhshQuery sendGuess queryTarget + + val message = StringBuilder(NBNHHSH_RESULT_HEAD_HTML) + + import cc.sukazyo.cono.morny.Log.logger + 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)) + message ++= s"\n\n[[ ${h(_word.name)} ]]" + logger debug s"**used [${_word.name}]" + if (_word.trans != null) for (_trans <- _word.trans) + message ++= s"\n* ${h(_trans)}" + logger debug s"**used [${_word.name}] used `${_trans}``" + if (_word.inputting != null) + logger debug s"**used [${_word.name}] inputting" + if (_word.trans != null) + message += '\n' + message ++= " maybe:" + for (_inputting <- _word.inputting) + logger debug s"**used [${_word.name}] used-i ${_inputting}" + message ++= s"\n` ${h(_inputting)}" + logger debug s"**exec as ${_word.name}" + } + + MornyCoeur.extra exec SendMessage( + event.message.chat.id, + message toString + ).parseMode(ParseMode HTML).replyToMessageId(event.message.messageId) + + } catch case e: IOException => { + MornyCoeur.extra exec SendMessage( + event.message.chat.id, + s"""[Exception] in query: + |${h(e.getMessage)} + |""".stripMargin + ) + } + + } + +} 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 new file mode 100644 index 0000000..4d453da --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/Testing.scala @@ -0,0 +1,30 @@ +package cc.sukazyo.cono.morny.bot.command + +import cc.sukazyo.cono.morny.MornyCoeur +import cc.sukazyo.cono.morny.util.tgapi.InputCommand +import com.pengrad.telegrambot.model.Update +import com.pengrad.telegrambot.model.request.ParseMode +import com.pengrad.telegrambot.request.SendMessage + +import javax.annotation.Nonnull +import javax.annotation.Nullable +import scala.language.postfixOps + +object Testing extends ISimpleCommand { + + override def getName: String = "test" + override def getAliases: Array[String] = null + + override def execute (command: InputCommand, event: Update): Unit = { + + val a = StringBuilder("value") + a ++= "Changed" + + MornyCoeur.extra exec new SendMessage( + event.message.chat.id, + "Just a TEST command. num is:" + (a toString) + ).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 new file mode 100644 index 0000000..c870e8e --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/喵呜.scala @@ -0,0 +1,67 @@ +package cc.sukazyo.cono.morny.bot.command + +import cc.sukazyo.cono.morny.MornyCoeur +import cc.sukazyo.cono.morny.data.TelegramStickers +import cc.sukazyo.cono.morny.util.tgapi.InputCommand +import com.pengrad.telegrambot.model.request.ParseMode +import com.pengrad.telegrambot.model.{Message, Update} +import com.pengrad.telegrambot.request.{SendMessage, SendSticker} + +import javax.swing.text.html.HTML +import scala.annotation.unused +import scala.language.postfixOps + +@SuppressWarnings(Array("NonAsciiCharacters")) +object 喵呜 { + + object 抱抱 extends ISimpleCommand { + override def getName: String = "抱抱" + override def getAliases: Array[String] = Array() + override def execute (command: InputCommand, event: Update): Unit = + replyingSet(event, "贴贴", "贴贴") + } + + object 揉揉 extends ISimpleCommand { + override def getName: String = "揉揉" + override def getAliases: Array[String] = Array() + override def execute (command: InputCommand, event: Update): Unit = + replyingSet(event, "蹭蹭", "摸摸") + } + + object 蹭蹭 extends ISimpleCommand { + override def getName: String = "蹭蹭" + override def getAliases: Array[String] = Array() + override def execute (command: InputCommand, event: Update): Unit = + replyingSet(event, "揉揉", "蹭蹭") + } + + object 贴贴 extends ISimpleCommand { + override def getName: String = "贴贴" + override def getAliases: Array[String] = Array() + override def execute (command: InputCommand, event: Update): Unit = + replyingSet(event, "贴贴", "贴贴") + } + + 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 = { + MornyCoeur.extra exec new SendSticker( + event.message.chat.id, + TelegramStickers ID_PROGYNOVA + ).replyToMessageId(event.message.messageId) + } + } + + private def replyingSet (event: Update, whileRec: String, whileNew: String): Unit = { + val isNew = event.message.replyToMessage == null; + val target = if (isNew) event.message else event.message.replyToMessage + MornyCoeur.extra exec new SendMessage( + event.message.chat.id, + if (isNew) whileNew else whileRec + ).replyToMessageId(target.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 new file mode 100644 index 0000000..67da3f5 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/私わね.scala @@ -0,0 +1,26 @@ +package cc.sukazyo.cono.morny.bot.command + +import cc.sukazyo.cono.morny.MornyCoeur +import cc.sukazyo.cono.morny.util.tgapi.InputCommand +import cc.sukazyo.cono.morny.util.CommonRandom.probabilityTrue +import com.pengrad.telegrambot.model.Update +import com.pengrad.telegrambot.request.SendMessage + +object 私わね extends ISimpleCommand { + + override def getName: String = "me" + override def getAliases: Array[String] = Array() + + override def execute (command: InputCommand, event: Update): Unit = { + + if (probabilityTrue(521)) { + val text = "/打假" + MornyCoeur.extra exec new SendMessage( + event.message.chat.id, + text + ).replyToMessageId(event.message.messageId) + } + + } + +} 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 new file mode 100644 index 0000000..1f51e4d --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnCallMe.scala @@ -0,0 +1,90 @@ +package cc.sukazyo.cono.morny.bot.event + +import cc.sukazyo.cono.morny.Log.logger +import cc.sukazyo.cono.morny.MornyCoeur +import cc.sukazyo.cono.morny.bot.api.EventListener +import cc.sukazyo.cono.morny.data.TelegramStickers +import cc.sukazyo.cono.morny.util.tgapi.formatting.TGToString +import com.pengrad.telegrambot.model.request.ParseMode +import com.pengrad.telegrambot.model.{Chat, Message, Update, User} +import com.pengrad.telegrambot.request.{ForwardMessage, GetChat, SendMessage, SendSticker} + +import scala.language.postfixOps + +object OnCallMe extends EventListener { + + private val me = MornyCoeur.config.trustedMaster + + override def onMessage (update: Update): Boolean = { + + if update.message.text == null then return false + if update.message.chat.`type` != (Chat.Type Private) then return false + + (update.message.text toLowerCase) match + case "steam" | "sbeam" | "sdeam" => + requestItem(update.message.from, "STEAM LIBRARY") + case "hana paresu" | "花宫" | "内群" => + requestItem(update.message.from, "Hana Paresu") + case "dinner" | "lunch" | "breakfast" | "meal" | "eating" | "安妮今天吃什么" => + requestLastDinner(update.message) + case cc if cc startsWith "cc::" => + requestCustom(update.message) + case _ => + return false + + MornyCoeur.extra exec SendSticker( + update.message.chat.id, + TelegramStickers ID_SENT + ).replyToMessageId(update.message.messageId) + true + + } + + private def requestItem (user: User, itemHTML: String, extra: String|Null = null): Unit = + MornyCoeur.extra exec SendMessage( + me, + s"""request $itemHTML + |from ${(TGToString as user) fullnameRefHtml}${if extra == null then "" else "\n"+extra}""" + .stripMargin + ).parseMode(ParseMode HTML) + + private def requestLastDinner (req: Message): Unit = { + var isAllowed = false + var lastDinnerData: Message|Null = null + if (MornyCoeur.trustedInstance isTrustedForDinnerRead req.from.id) { + lastDinnerData = (MornyCoeur.extra exec GetChat(MornyCoeur.config.dinnerChatId)).chat.pinnedMessage + val sendResp = MornyCoeur.extra exec ForwardMessage( + req.from.id, + lastDinnerData.forwardFromChat.id, + lastDinnerData.forwardFromMessageId + ) + import cc.sukazyo.cono.morny.util.CommonFormat.{formatDate, formatDuration} + import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h + def lastDinner_dateMillis: Long = lastDinnerData.forwardDate longValue; + MornyCoeur.extra exec SendMessage( + req.from.id, + "on %s [UTC+8]\n- %s before".formatted( + h(formatDate(lastDinner_dateMillis, 8)), + h(formatDuration(lastDinner_dateMillis)) + ) + ).parseMode(ParseMode HTML).replyToMessageId(sendResp.message.messageId) + isAllowed = true + } else { + MornyCoeur.extra exec SendSticker( + req.from.id, + TelegramStickers ID_403 + ).replyToMessageId(req.messageId) + } + import Math.abs + requestItem( + req.from, "Last Annie Dinner", + if isAllowed then s"Allowed and returned https://t.me/c/${abs(lastDinnerData.forwardFromChat.id+1000000000000L)}/${lastDinnerData.forwardFromMessageId}" + else "Forbidden by perm check." + ) + } + + private def requestCustom (message: Message): Unit = + requestItem(message.from, "[???]") + MornyCoeur.extra exec ForwardMessage(me, message.chat.id, message.messageId) + +} 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 new file mode 100644 index 0000000..96f2ad0 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnInlineQuery.scala @@ -0,0 +1,37 @@ +package cc.sukazyo.cono.morny.bot.event + +import cc.sukazyo.cono.morny.MornyCoeur +import cc.sukazyo.cono.morny.bot.api.{EventListener, InlineQueryUnit} +import com.pengrad.telegrambot.model.Update +import com.pengrad.telegrambot.model.request.InlineQueryResult +import com.pengrad.telegrambot.request.AnswerInlineQuery + +import scala.collection.mutable.ListBuffer +import scala.language.postfixOps +import scala.reflect.ClassTag + +object OnInlineQuery extends EventListener { + + override def onInlineQuery (update: Update): Boolean = { + + val results: List[InlineQueryUnit[_]] = MornyCoeur.queryManager query update + + var cacheTime = Int.MaxValue + var isPersonal = InlineQueryUnit.DEFAULT_INLINE_PERSONAL_RESP + val resultAnswers = ListBuffer[InlineQueryResult[_]]() + for (r <- results) { + if (cacheTime > r.cacheTime) cacheTime = r.cacheTime + if (r isPersonal) isPersonal = true + resultAnswers += r.result + } + + if (results isEmpty) return false + + MornyCoeur.extra exec AnswerInlineQuery( + update.inlineQuery.id, resultAnswers toArray:_* + ).cacheTime(cacheTime).isPersonal(isPersonal) + true + + } + +} 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 new file mode 100644 index 0000000..2e21f63 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnUserRandom.scala @@ -0,0 +1,38 @@ +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 scala.language.postfixOps + +object OnUserRandom extends EventListener { + + private val USER_OR_QUERY = "(.+)(?:还是|or)(.+)"r + private val USER_IF_QUERY = "(.+)[吗?|?]+$"r + + override def onMessage(update: Update): Boolean = { + + if update.message.text == null then return false + if update.message.text startsWith "/" then return false + + import cc.sukazyo.cono.morny.util.CommonRandom.iif + val query = update.message.text substring 1 + val result: String|Null = query match + case USER_OR_QUERY(_con1, _con2) => + if iif then _con1 else _con2 + case USER_IF_QUERY(_con) => + (if iif then "不" else "") + _con + case _ => null + + if result == null then return false + + MornyCoeur.extra exec SendMessage( + update.message.chat.id, result + ).replyToMessageId(update.message.messageId) + true + + } + +} 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 new file mode 100644 index 0000000..1970726 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnUserSlashAction.scala @@ -0,0 +1,67 @@ +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.UniversalCommand +import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h +import cc.sukazyo.cono.morny.util.tgapi.formatting.TGToString +import com.pengrad.telegrambot.model.Update +import com.pengrad.telegrambot.model.request.ParseMode +import com.pengrad.telegrambot.request.SendMessage + +import scala.language.postfixOps + +object OnUserSlashAction extends EventListener { + + private val TG_FORMAT = "^\\w+(@\\w+)?$"r + + override def onMessage (update: Update): Boolean = { + + val text = update.message.text; + if text == null then return false + + if (text startsWith "/") { + + val actions = UniversalCommand format text + actions(0) = actions(0) substring 1 + + actions(0) + + actions(0) match + case TG_FORMAT(_) => + return false + case x if x contains "/" => return false + + val isHardParse = actions(0) isBlank + def hp_len(i: Int) = if isHardParse then i+1 else i + if isHardParse && actions.length < 2 then return false + val v_verb = actions(hp_len(0)) + val hasObject = actions.length != hp_len(1) + val v_object = + if hasObject then + actions slice(hp_len(1), actions.length) mkString(" ") + else "" + val origin = update.message + val target = + if update.message.replyToMessage == null then + origin + else update.message.replyToMessage + + MornyCoeur.extra exec SendMessage( + update.message.chat.id, + "%s %s%s %s %s!".format( + (TGToString as origin) getSenderFirstNameRefHtml, + h(v_verb), if hasObject then "" else "了", + if (origin == target) + s"自己" + else (TGToString as target) getSenderFirstNameRefHtml, + if hasObject then h(v_object+" ") else "" + ) + ).parseMode(ParseMode HTML).replyToMessageId(update.message.messageId) + true + + } else false + + } + +} 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 new file mode 100644 index 0000000..d03a05c --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/query/ITelegramQuery.scala @@ -0,0 +1,11 @@ +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 { + + def query (event: Update): List[InlineQueryUnit[_]] | Null + +} \ No newline at end of file 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 new file mode 100644 index 0000000..faeaefb --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/query/MornyQueries.scala @@ -0,0 +1,27 @@ +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 + +import scala.collection.mutable.ListBuffer + +class MornyQueries { + + private val queryInstances = Set[ITelegramQuery]( + RawText, + MyInformation, + ShareToolTwitter, + ShareToolBilibili + ) + + def query (event: Update): List[InlineQueryUnit[_]] = { + val results = ListBuffer[InlineQueryUnit[_]]() + for (instance <- queryInstances) { + val r = instance query event + if (r != null) results ++= r + } + results.result() + } + +} 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 new file mode 100644 index 0000000..c98feb6 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/query/MyInformation.scala @@ -0,0 +1,31 @@ +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 +import com.pengrad.telegrambot.model.request.{InlineQueryResultArticle, InputTextMessageContent, ParseMode} + +import scala.language.postfixOps + +object MyInformation extends ITelegramQuery { + + private val ID_PREFIX = "[morny/info/me]" + private val TITLE = "My Account Information" + + override def query (event: Update): List[InlineQueryUnit[_]] | Null = { + + if (event.inlineQuery.query == null || (event.inlineQuery.query isBlank)) return null + + List( + InlineQueryUnit(InlineQueryResultArticle( + inlineIds(ID_PREFIX), TITLE, + new InputTextMessageContent( + TelegramUserInformation informationOutputHTML event.inlineQuery.from + ).parseMode(ParseMode HTML) + )).isPersonal(true).cacheTime(10) + ) + + } + +} 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 new file mode 100644 index 0000000..2d19149 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/query/RawText.scala @@ -0,0 +1,27 @@ +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} + +import scala.language.postfixOps + +object RawText extends ITelegramQuery { + + private val ID_PREFIX = "[morny/r/text]" + private val TITLE = "Raw Text" + + override def query (event: Update): List[InlineQueryUnit[_]] | Null = { + + if (event.inlineQuery.query == null || (event.inlineQuery.query isBlank)) return null + + List( + InlineQueryUnit(InlineQueryResultArticle( + inlineIds(ID_PREFIX, event.inlineQuery.query), TITLE, + InputTextMessageContent(event.inlineQuery.query) + )) + ) + + } + +} 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 new file mode 100644 index 0000000..90288e2 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/query/ShareToolBilibili.scala @@ -0,0 +1,77 @@ +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 +import com.pengrad.telegrambot.model.request.{InlineQueryResultArticle, InputTextMessageContent, ParseMode} + +import scala.language.postfixOps +import scala.util.matching.Regex + +object ShareToolBilibili extends ITelegramQuery { + + private val TITLE_BILI_AV = "[bilibili] Share video / av" + private val TITLE_BILI_BV = "[bilibili] Share video / BV" + private val ID_PREFIX_BILI_AV = "[morny/share/bili/av]" + private val ID_PREFIX_BILI_BV = "[morny/share/bili/bv]" + private val LINK_PREFIX = "https://bilibili.com/video/" + private val REGEX_BILI_VIDEO: Regex = "^(?:(?:https?://)?(?:www\\.)?bilibili\\.com(?:/s)?/video/((?:av|AV)(\\d{1,12})|(?:bv|BV)([A-HJ-NP-Za-km-z1-9]{10}))/?(\\?(?:p=(\\d+))?.*)?|(?:av|AV)(\\d{1,12})|(?:bv|BV)([A-HJ-NP-Za-km-z1-9]{10}))$"r + private val SHARE_FORMAT_HTML = "%s" + + override def query (event: Update): List[InlineQueryUnit[_]] | Null = { + + if (event.inlineQuery.query == null) return null + + event.inlineQuery.query match + case REGEX_BILI_VIDEO(_1, _2, _3, _4, _5, _6, _7) => + + logger debug + s"""====== Share Tool Bilibili Catch ok + |1: ${_1} + |2: ${_2} + |3: ${_3} + |4: ${_4} + |5: ${_5} + |6: ${_6} + |7: ${_7}""" + .stripMargin + + var av = if (_2 != null) _2 else if (_6 != null) _6 else null + var bv = if (_3!=null) _3 else if (_7!=null) _7 else null + logger trace s"catch id av[$av] bv[$bv]" + val part: Int|Null = if (_5!=null) _5 toInt else null + logger trace s"catch video part[$part]" + + if (av == null) { + assert (bv != null) + av = BiliTool.toAv(bv) toString; + logger trace s"converted bv[$av] to av[$av]" + } else { + bv = BiliTool.toBv(av toLong) + logger trace s"converted av[$av] to bv[$bv]" + } + + val id_av = s"av$av" + val id_bv = s"BV$bv" + val linkParams = if (part!=null) s"?p=$part" else "" + val link_av = LINK_PREFIX + id_av + linkParams + val link_bv = LINK_PREFIX + id_bv + linkParams + + List( + InlineQueryUnit(InlineQueryResultArticle( + inlineIds(ID_PREFIX_BILI_AV+av), TITLE_BILI_AV+av, + InputTextMessageContent(SHARE_FORMAT_HTML.format(link_av, id_av)).parseMode(ParseMode HTML) + )), + InlineQueryUnit(InlineQueryResultArticle( + inlineIds(ID_PREFIX_BILI_BV + bv), TITLE_BILI_BV + bv, + InputTextMessageContent(SHARE_FORMAT_HTML.format(link_bv, id_bv)).parseMode(ParseMode HTML) + )) + ) + + case _ => null + + } + +} 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 new file mode 100644 index 0000000..9427dca --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/query/ShareToolTwitter.scala @@ -0,0 +1,42 @@ +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 + +import cc.sukazyo.cono.morny.util.tgapi.formatting.NamedUtils.inlineIds + +import scala.language.postfixOps +import scala.util.matching.Regex + +object ShareToolTwitter extends ITelegramQuery { + + val TITLE_VX = "[tweet] Share as VxTwitter" + val TITLE_VX_COMBINED = "[tweet] Share as VxTwitter(combination)" + val ID_PREFIX_VX = "[morny/share/twitter/vxtwi]" + val ID_PREFIX_VX_COMBINED = "[morny/share/twitter/vxtwi_combine]" + val REGEX_TWEET_LINK: Regex = "^(?:https?://)?((?:(?:c\\.)?vx|fx|www\\.)?twitter\\.com)/((\\w+)/status/(\\d+)(?:/photo/(\\d+))?)/?(\\?[\\w&=-]+)?$"r + + override def query (event: Update): List[InlineQueryUnit[_]] | Null = { + + if (event.inlineQuery.query == null) return null + + event.inlineQuery.query match + + case REGEX_TWEET_LINK(_1, _2, _) => + List( + InlineQueryUnit(InlineQueryResultArticle( + inlineIds(ID_PREFIX_VX+event.inlineQuery.query), TITLE_VX, + s"https://vxtwitter.com/$_2" + )), + InlineQueryUnit(InlineQueryResultArticle( + inlineIds(ID_PREFIX_VX_COMBINED+event.inlineQuery.query), TITLE_VX_COMBINED, + s"https://c.vxtwitter.com/$_2" + )) + ) + + case _ => null + + } + +} 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 new file mode 100644 index 0000000..65abaca --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/data/ip186/IP186QueryHandler.scala @@ -0,0 +1,41 @@ +package cc.sukazyo.cono.morny.data.ip186 + +import okhttp3.{OkHttpClient, Request} + +import java.io.IOException +import scala.language.postfixOps +import scala.util.Using + +object IP186QueryHandler { + + private val SITE_URL = "https://ip.186526.xyz/" + private val QUERY_PARAM_IP = "type=json&format=true" + private val QUERY_PARAM_WHOIS = "type=plain" + + private val httpClient = OkHttpClient() + + @throws[IOException] + def query_ip (ip: String): IP186Response = + commonQuery(SITE_URL + ip, QUERY_PARAM_IP) + + @throws[IOException] + def query_whois (domain: String): IP186Response = + commonQuery(SITE_URL+"whois/"+domain, QUERY_PARAM_WHOIS) + + @throws[IOException] + def query_whoisPretty (domain: String): IP186Response = + val raw = query_whois(domain) + IP186Response(raw.url, raw.body substring(0, (raw.body indexOf "<<<")+3)) + + @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) + } + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/data/ip186/IP186Response.scala b/src/main/scala/cc/sukazyo/cono/morny/data/ip186/IP186Response.scala new file mode 100644 index 0000000..6fcad79 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/data/ip186/IP186Response.scala @@ -0,0 +1,3 @@ +package cc.sukazyo.cono.morny.data.ip186 + +case class IP186Response (url: String, body: String) From 1a31a22cd9fc7a84a00e060bbc27786d13413b05 Mon Sep 17 00:00:00 2001 From: Eyre_S Date: Thu, 7 Sep 2023 22:15:06 +0800 Subject: [PATCH 2/5] 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 } } From ddfe77350e17cce79e8affa5b74531d3d061b05a Mon Sep 17 00:00:00 2001 From: Eyre_S Date: Sun, 10 Sep 2023 22:43:39 +0800 Subject: [PATCH 3/5] scala port stage3 (not tested) --- build.gradle | 41 +-- gradle.properties | 2 +- .../cc/sukazyo/cono/morny/util/BiliTool.java | 0 .../cono/morny/util/CommonConvert.java | 0 .../cono/morny/util/CommonEncrypt.java | 0 .../sukazyo/cono/morny/util/CommonFormat.java | 0 .../sukazyo/cono/morny/util/CommonRandom.java | 0 .../cc/sukazyo/cono/morny/util/FileUtils.java | 0 .../sukazyo/cono/morny/util/OkHttpPublic.java | 0 .../cono/morny/util/UniversalCommand.java | 0 .../cono/morny/util/tgapi/ExtraAction.java | 0 .../cono/morny/util/tgapi/InputCommand.java | 0 .../cono/morny/util/tgapi/Standardize.java | 0 .../tgapi/event/EventRuntimeException.java | 0 .../util/tgapi/formatting/MsgEscape.java | 0 .../util/tgapi/formatting/NamedUtils.java | 0 .../util/tgapi/formatting/TGToString.java | 0 .../tgapi/formatting/TGToStringFromChat.java | 0 .../formatting/TGToStringFromMessage.java | 0 .../tgapi/formatting/TGToStringFromUser.java | 0 .../formatting/TelegramUserInformation.java | 0 src/main/old/cc/sukazyo/cono/morny/Log.java | 58 ---- .../old/cc/sukazyo/cono/morny/MornyAbout.java | 31 -- .../cc/sukazyo/cono/morny/MornyAssets.java | 19 -- .../old/cc/sukazyo/cono/morny/MornyCoeur.java | 310 ------------------ .../cc/sukazyo/cono/morny/MornySystem.java | 145 -------- .../cc/sukazyo/cono/morny/MornyTrusted.java | 42 --- .../sukazyo/cono/morny/bot/command/Roll.java | 4 - .../cono/morny/bot/command/package-info.java | 7 - .../morny/bot/event/OnActivityRecord.java | 28 -- .../bot/event/OnKuohuanhuanNeedSleep.java | 39 --- .../morny/bot/event/OnRandomlyTriggered.java | 27 -- .../cono/morny/daemon/MedicationTimer.java | 98 ------ .../cono/morny/daemon/MornyDaemons.java | 34 -- .../cono/morny/daemon/MornyReport.java | 159 --------- .../cono/morny/daemon/TrackerDataManager.java | 174 ---------- .../cono/morny/data/TelegramImages.java | 81 ----- .../cono/morny/data/TelegramStickers.java | 87 ----- .../scala/cc/sukazyo/cono/morny/Log.scala | 29 ++ .../cc/sukazyo/cono/morny/MornyAbout.scala | 17 + .../cc/sukazyo/cono/morny/MornyAssets.scala | 9 + .../cc/sukazyo/cono/morny/MornyCoeur.scala | 149 +++++++++ .../cc/sukazyo/cono/morny/MornyConfig.java | 6 +- .../cc/sukazyo/cono/morny/MornySystem.scala | 48 +++ .../cc/sukazyo/cono/morny/MornyTrusted.scala | 16 + .../cc/sukazyo/cono/morny/ServerMain.scala | 6 +- .../morny/bot/command/DirectMsgClear.scala | 4 +- .../cono/morny/bot/command/Encryptor.scala | 4 +- .../cono/morny/bot/command/EventHack.scala | 2 +- .../morny/bot/command/GetUsernameAndId.scala | 2 +- .../cono/morny/bot/command/IP186Query.scala | 4 +- .../morny/bot/command/MornyCommands.scala | 13 +- .../morny/bot/command/MornyInformation.scala | 57 ++-- .../morny/bot/command/MornyManagers.scala | 4 +- .../cono/morny/bot/event/OnCallMe.scala | 4 +- .../cono/morny/bot/event/OnCallMsgSend.scala | 9 +- .../cono/morny/bot/event/OnInlineQuery.scala | 4 +- .../bot/event/OnMedicationNotifyApply.scala | 4 +- .../morny/bot/event/OnTelegramCommand.scala | 2 +- .../cono/morny/bot/query/MornyQueries.scala | 2 +- .../cono/morny/bot/query/MyInformation.scala | 2 +- .../cono/morny/daemon/MedicationTimer.scala | 90 +++++ .../cono/morny/daemon/MornyDaemons.scala | 29 ++ .../cono/morny/daemon/MornyReport.scala | 122 +++++++ .../cono/morny/data/TelegramImages.scala | 38 +++ .../cono/morny/data/TelegramStickers.java | 53 +++ .../cono/morny/internal/BuildConfigField.java | 0 .../cono/morny/internal/ScalaJavaConv.scala | 12 + .../java/cc/sukazyo/cono/morny/MornyCLI.java | 2 +- .../morny/daemon/TestMedicationTimer.java | 6 +- 70 files changed, 712 insertions(+), 1423 deletions(-) rename src/main/{old => java}/cc/sukazyo/cono/morny/util/BiliTool.java (100%) rename src/main/{old => java}/cc/sukazyo/cono/morny/util/CommonConvert.java (100%) rename src/main/{old => java}/cc/sukazyo/cono/morny/util/CommonEncrypt.java (100%) rename src/main/{old => java}/cc/sukazyo/cono/morny/util/CommonFormat.java (100%) rename src/main/{old => java}/cc/sukazyo/cono/morny/util/CommonRandom.java (100%) rename src/main/{old => java}/cc/sukazyo/cono/morny/util/FileUtils.java (100%) rename src/main/{old => java}/cc/sukazyo/cono/morny/util/OkHttpPublic.java (100%) rename src/main/{old => java}/cc/sukazyo/cono/morny/util/UniversalCommand.java (100%) rename src/main/{old => java}/cc/sukazyo/cono/morny/util/tgapi/ExtraAction.java (100%) rename src/main/{old => java}/cc/sukazyo/cono/morny/util/tgapi/InputCommand.java (100%) rename src/main/{old => java}/cc/sukazyo/cono/morny/util/tgapi/Standardize.java (100%) rename src/main/{old => java}/cc/sukazyo/cono/morny/util/tgapi/event/EventRuntimeException.java (100%) rename src/main/{old => java}/cc/sukazyo/cono/morny/util/tgapi/formatting/MsgEscape.java (100%) rename src/main/{old => java}/cc/sukazyo/cono/morny/util/tgapi/formatting/NamedUtils.java (100%) rename src/main/{old => java}/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToString.java (100%) rename src/main/{old => java}/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromChat.java (100%) rename src/main/{old => java}/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromMessage.java (100%) rename src/main/{old => java}/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromUser.java (100%) rename src/main/{old => java}/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramUserInformation.java (100%) delete mode 100644 src/main/old/cc/sukazyo/cono/morny/Log.java delete mode 100644 src/main/old/cc/sukazyo/cono/morny/MornyAbout.java delete mode 100644 src/main/old/cc/sukazyo/cono/morny/MornyAssets.java delete mode 100644 src/main/old/cc/sukazyo/cono/morny/MornyCoeur.java delete mode 100644 src/main/old/cc/sukazyo/cono/morny/MornySystem.java delete mode 100644 src/main/old/cc/sukazyo/cono/morny/MornyTrusted.java delete mode 100644 src/main/old/cc/sukazyo/cono/morny/bot/command/Roll.java delete mode 100644 src/main/old/cc/sukazyo/cono/morny/bot/command/package-info.java delete mode 100644 src/main/old/cc/sukazyo/cono/morny/bot/event/OnActivityRecord.java delete mode 100644 src/main/old/cc/sukazyo/cono/morny/bot/event/OnKuohuanhuanNeedSleep.java delete mode 100644 src/main/old/cc/sukazyo/cono/morny/bot/event/OnRandomlyTriggered.java delete mode 100644 src/main/old/cc/sukazyo/cono/morny/daemon/MedicationTimer.java delete mode 100644 src/main/old/cc/sukazyo/cono/morny/daemon/MornyDaemons.java delete mode 100644 src/main/old/cc/sukazyo/cono/morny/daemon/MornyReport.java delete mode 100644 src/main/old/cc/sukazyo/cono/morny/daemon/TrackerDataManager.java delete mode 100644 src/main/old/cc/sukazyo/cono/morny/data/TelegramImages.java delete mode 100644 src/main/old/cc/sukazyo/cono/morny/data/TelegramStickers.java create mode 100644 src/main/scala/cc/sukazyo/cono/morny/Log.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/MornyAbout.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/MornyAssets.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/MornyCoeur.scala rename src/main/{old => scala}/cc/sukazyo/cono/morny/MornyConfig.java (97%) create mode 100644 src/main/scala/cc/sukazyo/cono/morny/MornySystem.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/MornyTrusted.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/daemon/MedicationTimer.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/daemon/MornyDaemons.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/daemon/MornyReport.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/data/TelegramImages.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/data/TelegramStickers.java rename src/main/{old => scala}/cc/sukazyo/cono/morny/internal/BuildConfigField.java (100%) create mode 100644 src/main/scala/cc/sukazyo/cono/morny/internal/ScalaJavaConv.scala diff --git a/build.gradle b/build.gradle index 4d45291..f0041ee 100644 --- a/build.gradle +++ b/build.gradle @@ -52,7 +52,7 @@ final JavaVersion proj_java = JavaVersion.VERSION_17 final Charset proj_file_encoding = StandardCharsets.UTF_8 final proj_scala_api = 3 //final proj_scala_lib = proj_scala_api+'.4.0-RC1-bin-20230901-89e8dba-NIGHTLY' -final proj_scala_lib = proj_scala_api+'.3.1-RC7' +final proj_scala_lib = proj_scala_api+'.3.1' String publish_local_url = null String publish_remote_url = null String publish_remote_username = null @@ -89,35 +89,26 @@ dependencies { } -sourceSets { - main { - scala { srcDirs = ['src/main/scala', 'src/main/old'] } - } +tasks.withType(JavaCompile).configureEach { + + sourceCompatibility proj_java.getMajorVersion() + targetCompatibility proj_java.getMajorVersion() + + options.encoding = proj_file_encoding.name() + } -scala { +tasks.withType(ScalaCompile).configureEach { - compileJava { - - sourceCompatibility proj_java.getMajorVersion() - targetCompatibility proj_java.getMajorVersion() - - options.encoding = proj_file_encoding.name() - - } + sourceCompatibility proj_java.getMajorVersion() + targetCompatibility proj_java.getMajorVersion() - 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") - - } + options.encoding = proj_file_encoding.name() + scalaCompileOptions.encoding = proj_file_encoding.name() + scalaCompileOptions.additionalParameters.add "-language:postfixOps" +// scalaCompileOptions.additionalParameters.add("-Yexplicit-nulls") + } test { diff --git a/gradle.properties b/gradle.properties index 4f1df34..9ce1455 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 = scalaport2 +VERSION_DELTA = scalaport3 CODENAME = beiping diff --git a/src/main/old/cc/sukazyo/cono/morny/util/BiliTool.java b/src/main/java/cc/sukazyo/cono/morny/util/BiliTool.java similarity index 100% rename from src/main/old/cc/sukazyo/cono/morny/util/BiliTool.java rename to src/main/java/cc/sukazyo/cono/morny/util/BiliTool.java diff --git a/src/main/old/cc/sukazyo/cono/morny/util/CommonConvert.java b/src/main/java/cc/sukazyo/cono/morny/util/CommonConvert.java similarity index 100% rename from src/main/old/cc/sukazyo/cono/morny/util/CommonConvert.java rename to src/main/java/cc/sukazyo/cono/morny/util/CommonConvert.java diff --git a/src/main/old/cc/sukazyo/cono/morny/util/CommonEncrypt.java b/src/main/java/cc/sukazyo/cono/morny/util/CommonEncrypt.java similarity index 100% rename from src/main/old/cc/sukazyo/cono/morny/util/CommonEncrypt.java rename to src/main/java/cc/sukazyo/cono/morny/util/CommonEncrypt.java diff --git a/src/main/old/cc/sukazyo/cono/morny/util/CommonFormat.java b/src/main/java/cc/sukazyo/cono/morny/util/CommonFormat.java similarity index 100% rename from src/main/old/cc/sukazyo/cono/morny/util/CommonFormat.java rename to src/main/java/cc/sukazyo/cono/morny/util/CommonFormat.java diff --git a/src/main/old/cc/sukazyo/cono/morny/util/CommonRandom.java b/src/main/java/cc/sukazyo/cono/morny/util/CommonRandom.java similarity index 100% rename from src/main/old/cc/sukazyo/cono/morny/util/CommonRandom.java rename to src/main/java/cc/sukazyo/cono/morny/util/CommonRandom.java diff --git a/src/main/old/cc/sukazyo/cono/morny/util/FileUtils.java b/src/main/java/cc/sukazyo/cono/morny/util/FileUtils.java similarity index 100% rename from src/main/old/cc/sukazyo/cono/morny/util/FileUtils.java rename to src/main/java/cc/sukazyo/cono/morny/util/FileUtils.java diff --git a/src/main/old/cc/sukazyo/cono/morny/util/OkHttpPublic.java b/src/main/java/cc/sukazyo/cono/morny/util/OkHttpPublic.java similarity index 100% rename from src/main/old/cc/sukazyo/cono/morny/util/OkHttpPublic.java rename to src/main/java/cc/sukazyo/cono/morny/util/OkHttpPublic.java diff --git a/src/main/old/cc/sukazyo/cono/morny/util/UniversalCommand.java b/src/main/java/cc/sukazyo/cono/morny/util/UniversalCommand.java similarity index 100% rename from src/main/old/cc/sukazyo/cono/morny/util/UniversalCommand.java rename to src/main/java/cc/sukazyo/cono/morny/util/UniversalCommand.java diff --git a/src/main/old/cc/sukazyo/cono/morny/util/tgapi/ExtraAction.java b/src/main/java/cc/sukazyo/cono/morny/util/tgapi/ExtraAction.java similarity index 100% rename from src/main/old/cc/sukazyo/cono/morny/util/tgapi/ExtraAction.java rename to src/main/java/cc/sukazyo/cono/morny/util/tgapi/ExtraAction.java diff --git a/src/main/old/cc/sukazyo/cono/morny/util/tgapi/InputCommand.java b/src/main/java/cc/sukazyo/cono/morny/util/tgapi/InputCommand.java similarity index 100% rename from src/main/old/cc/sukazyo/cono/morny/util/tgapi/InputCommand.java rename to src/main/java/cc/sukazyo/cono/morny/util/tgapi/InputCommand.java diff --git a/src/main/old/cc/sukazyo/cono/morny/util/tgapi/Standardize.java b/src/main/java/cc/sukazyo/cono/morny/util/tgapi/Standardize.java similarity index 100% rename from src/main/old/cc/sukazyo/cono/morny/util/tgapi/Standardize.java rename to src/main/java/cc/sukazyo/cono/morny/util/tgapi/Standardize.java diff --git a/src/main/old/cc/sukazyo/cono/morny/util/tgapi/event/EventRuntimeException.java b/src/main/java/cc/sukazyo/cono/morny/util/tgapi/event/EventRuntimeException.java similarity index 100% rename from src/main/old/cc/sukazyo/cono/morny/util/tgapi/event/EventRuntimeException.java rename to src/main/java/cc/sukazyo/cono/morny/util/tgapi/event/EventRuntimeException.java diff --git a/src/main/old/cc/sukazyo/cono/morny/util/tgapi/formatting/MsgEscape.java b/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/MsgEscape.java similarity index 100% rename from src/main/old/cc/sukazyo/cono/morny/util/tgapi/formatting/MsgEscape.java rename to src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/MsgEscape.java diff --git a/src/main/old/cc/sukazyo/cono/morny/util/tgapi/formatting/NamedUtils.java b/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/NamedUtils.java similarity index 100% rename from src/main/old/cc/sukazyo/cono/morny/util/tgapi/formatting/NamedUtils.java rename to src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/NamedUtils.java diff --git a/src/main/old/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToString.java b/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToString.java similarity index 100% rename from src/main/old/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToString.java rename to src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToString.java diff --git a/src/main/old/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromChat.java b/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromChat.java similarity index 100% rename from src/main/old/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromChat.java rename to src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromChat.java diff --git a/src/main/old/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromMessage.java b/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromMessage.java similarity index 100% rename from src/main/old/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromMessage.java rename to src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromMessage.java diff --git a/src/main/old/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromUser.java b/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromUser.java similarity index 100% rename from src/main/old/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromUser.java rename to src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromUser.java diff --git a/src/main/old/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramUserInformation.java b/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramUserInformation.java similarity index 100% rename from src/main/old/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramUserInformation.java rename to src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramUserInformation.java diff --git a/src/main/old/cc/sukazyo/cono/morny/Log.java b/src/main/old/cc/sukazyo/cono/morny/Log.java deleted file mode 100644 index 57ab124..0000000 --- a/src/main/old/cc/sukazyo/cono/morny/Log.java +++ /dev/null @@ -1,58 +0,0 @@ -package cc.sukazyo.cono.morny; - -import cc.sukazyo.messiva.formatter.SimpleFormatter; -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; - -/** - * Morny 的 log 管理器 - */ -public class Log { - - /** - * Morny 的 Logger 实例, - * messiva 更新 - * @since 0.4.1.1 - */ - public static final Logger logger = new Logger(new ConsoleAppender(new SimpleFormatter())).minLevel(LogLevel.INFO); - - /** - * Is the Debug mode enabled. - * - * @return if the minimal log level is equal or lower than DEBUG level. - */ - public static boolean debug () { - return logger.levelSetting.minLevel().level <= LogLevel.DEBUG.level; - } - - /** - * Switch the Debug log output enabled. - *

- * if enable the debug log output, all the Log regardless of LogLevel will be output. - * As default, if the debug log output is disabled, Logger will ignore the Logs level lower than INFO. - * - * @param debug switch enable the debug log output as true, or disable it as false. - */ - public static void debug (boolean debug) { - if (debug) logger.minLevel(LogLevel.ALL); - else logger.minLevel(LogLevel.INFO); - } - - /** - * 获取异常的堆栈信息. - * @param e 异常体 - * @return {@link String} 格式的异常的堆栈报告信息. - * @see 1.0.0-alpha5 - */ - 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/MornyAbout.java b/src/main/old/cc/sukazyo/cono/morny/MornyAbout.java deleted file mode 100644 index 3933d9b..0000000 --- a/src/main/old/cc/sukazyo/cono/morny/MornyAbout.java +++ /dev/null @@ -1,31 +0,0 @@ -package cc.sukazyo.cono.morny; - -import java.io.IOException; - -/** - * Some of the static information of Morny. - */ -public class MornyAbout { - - /** - * ASCII art of Morny Featured Image. - *

- * used for Coeur starting welcome screen. - *

- * stored at /assets_morny/texts/server-hello.txt - */ - public static final String MORNY_PREVIEW_IMAGE_ASCII; - static { - try { - MORNY_PREVIEW_IMAGE_ASCII = MornyAssets.pack.getResource("texts/server-hello.txt").readAsString(); - } catch (IOException e) { - throw new RuntimeException("Cannot read MORNY_PREVIEW_IMAGE_ASCII from assets pack", e); - } - } - - public static final String MORNY_SOURCECODE_LINK = "https://github.com/Eyre-S/Coeur-Morny-Cono"; - public static final String MORNY_SOURCECODE_SELF_HOSTED_MIRROR_LINK = "https://storage.sukazyo.cc/Eyre_S/Coeur-Morny-Cono"; - public static final String MORNY_ISSUE_TRACKER_LINK = "https://github.com/Eyre-S/Coeur-Morny-Cono/issues"; - public static final String MORNY_USER_GUIDE_LINK = "https://book.sukazyo.cc/morny"; - -} diff --git a/src/main/old/cc/sukazyo/cono/morny/MornyAssets.java b/src/main/old/cc/sukazyo/cono/morny/MornyAssets.java deleted file mode 100644 index 1fdfe7f..0000000 --- a/src/main/old/cc/sukazyo/cono/morny/MornyAssets.java +++ /dev/null @@ -1,19 +0,0 @@ -package cc.sukazyo.cono.morny; - -import cc.sukazyo.restools.ResourcesPackage; - -/** - * Morny assets manager. - * - * @see #pack - * @since 1.0.0-RC4 - */ -public class MornyAssets { - - /** - * Instance mirror of the Morny assets, the assets root is /src/main/resources/assets_morny/. - * @since 1.0.0-RC4 - */ - public static final ResourcesPackage pack = new ResourcesPackage(MornyAssets.class, "assets_morny"); - -} diff --git a/src/main/old/cc/sukazyo/cono/morny/MornyCoeur.java b/src/main/old/cc/sukazyo/cono/morny/MornyCoeur.java deleted file mode 100644 index e6d201d..0000000 --- a/src/main/old/cc/sukazyo/cono/morny/MornyCoeur.java +++ /dev/null @@ -1,310 +0,0 @@ -package cc.sukazyo.cono.morny; - -import cc.sukazyo.cono.morny.bot.api.TelegramUpdatesListener$; -import cc.sukazyo.cono.morny.bot.command.MornyCommands; -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; -import cc.sukazyo.cono.morny.util.tgapi.ExtraAction; -import com.pengrad.telegrambot.TelegramBot; -import com.pengrad.telegrambot.impl.FileApi; -import com.pengrad.telegrambot.model.User; -import com.pengrad.telegrambot.request.GetMe; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import static cc.sukazyo.cono.morny.Log.logger; - -/** - * Morny Cono 核心
- * - 的程序化入口类,保管着 morny 的核心属性
- */ -public class MornyCoeur { - - /** 当前程序的 Morny Coeur 实例 */ - private static MornyCoeur INSTANCE; - - /** 当前 Morny 的启动配置 */ - public final MornyConfig config; - - /** 当前 Morny 的{@link MornyTrusted 信任验证机}实例 */ - private final MornyTrusted trusted; - private final MornyQueries queryManager = new MornyQueries(); - - /** morny 的 bot 账户 */ - private final TelegramBot account; - private final ExtraAction extraActionInstance; - /** - * morny 的 bot 账户的用户名
- *
- * 这个字段将会在登陆成功后赋值为登录到的 bot 的 username。 - * 它应该是和 {@link #account} 的 username 同步的
- *
- * 如果在登陆之前就定义了此字段,则登陆代码会验证登陆的 bot 的 username - * 是否与定义的 username 符合。如果不符合则会报错。 - */ - public final String username; - /** - * morny 的 bot 账户的 telegram id
- *
- * 这个字段将会在登陆成功后赋值为登录到的 bot 的 id。 - */ - public final long userid; - /** - * morny 主程序启动时间
- * 用于统计数据 - */ - public static final long coeurStartTimestamp = ServerMain.systemStartupTime(); - - private Object whileExitReason = null; - - private record LogInResult(TelegramBot account, String username, long userid) { } - - /** - * 执行 bot 初始化 - * - * @param config Morny 实例的配置选项数据 - */ - private MornyCoeur (MornyConfig config) { - - this.config = config; - - configureSafeExit(); - - logger.info("args key:\n " + config.telegramBotKey); - if (config.telegramBotUsername != null) { - logger.info("login as:\n " + config.telegramBotUsername); - } - - try { - final LogInResult loginResult = login(config.telegramBotApiServer, config.telegramBotApiServer4File, config.telegramBotKey, config.telegramBotUsername); - this.account = loginResult.account; - this.username = loginResult.username; - this.userid = loginResult.userid; - this.trusted = new MornyTrusted(this); - StringBuilder trustedReadersDinnerIds = new StringBuilder(); - trusted.getTrustedReadersOfDinnerSet().forEach(id -> trustedReadersDinnerIds.append("\n ").append(id)); - logger.info(String.format(""" - trusted param set: - - master (id) - %d - - trusted chat (id) - %d - - trusted reader-of-dinner (id)%s""", - config.trustedMaster, config.trustedChat, trustedReadersDinnerIds - )); - } - catch (Exception e) { - RuntimeException ex = new RuntimeException("Cannot login to bot/api. :\n " + e.getMessage()); - logger.error(ex.getMessage()); - throw ex; - } - - this.extraActionInstance = ExtraAction.as(account); - - logger.info("Bot login succeed."); - - } - - /** - * 向外界暴露的 morny 初始化入口. - *

- * 如果 morny 已经初始化,则不会进行初始化,抛出错误消息并直接退出方法。 - * - * @see #MornyCoeur 程序初始化方法 - * @param config morny 实例的配置选项数据 - */ - public static void init (MornyConfig config) { - if (INSTANCE == null) { - - logger.info("Coeur Starting"); - INSTANCE = new MornyCoeur(config); - - MornyDaemons.start(); - - logger.info("start telegram events listening"); - MornyEventListeners.registerAllEvents(); - INSTANCE.account.setUpdatesListener(TelegramUpdatesListener$.MODULE$); - - if (config.commandLoginRefresh) { - logger.info("resetting telegram command list"); - MornyCommands.automaticTGListUpdate(); - } - - logger.info("Coeur start complete"); - return; - - } - logger.error("Coeur already started!!!"); - } - - /** - * 向所有的数据管理器发起保存数据的指令 - * @since 0.4.3.0 - */ - public void saveDataAll () { - TrackerDataManager.save(); - } - - /** - * 用于退出时进行缓存的任务处理等进行安全退出 - */ - private void exitCleanup () { - MornyDaemons.stop(); - if (config.commandLogoutClear) { - MornyCommands.automaticTGListRemove(); - } - } - - /** - * 为程序在虚拟机上添加退出钩子 - */ - private void configureSafeExit () { - Runtime.getRuntime().addShutdownHook(new Thread(this::exitCleanup, "exit-cleaning")); - } - - /** - * 登录 bot. - *

- * 会反复尝试三次进行登录。如果登录失败,则会直接抛出 RuntimeException 结束处理。 - * 会通过 GetMe 动作验证是否连接上了 telegram api 服务器, - * 同时也要求登录获得的 username 和 {@link #username} 声明值相等 - * - * @param api bot client 将会连接到的 telegram bot api 位置。 - * 填入 {@code null} 则使用默认的 {@code "https://api.telegram.org/bot"} - * @param api4File bot client 将会连接到的 telegram file api 位置。 - * 如果传入 {@code null} 则会跟随 {@param api} 选项的设定(具体为在 {@param api} 路径的后面添加 {@code /file} 路径)。 - * 如果两者都为 {@code null},则跟随默认的 {@value FileApi#FILE_API} - * @param key bot 的 api-token. 必要值 - * @param requireName 要求登录到的需要的 username,如果登陆后的 username 与此不同则会报错退出。 - * 填入 {@code null} 则表示不对 username 作要求 - * @return 成功登录后的 {@link TelegramBot} 对象 - */ - @Nonnull - private static LogInResult login ( - @Nullable String api, @Nullable String api4File, - @Nonnull String key, @Nullable String requireName - ) { - final TelegramBot.Builder accountConfig = new TelegramBot.Builder(key); - boolean isCustomApi = false; - String apiUrlSet = "https://api.telegram.org/bot"; - String api4FileUrlSet = FileApi.FILE_API; - if (api != null) { - api = api.endsWith("/") ? api.substring(0, api.length() - 1) : api; - accountConfig.apiUrl(apiUrlSet = api.endsWith("/bot")? api : api + "/bot"); - isCustomApi = true; - } - if (api4File != null) { - api4File = api4File.endsWith("/") ? api4File : api4File + "/"; - accountConfig.fileApiUrl(api4FileUrlSet = api4File.endsWith("/file/bot")? api4File : api4File + "/file/bot"); - isCustomApi = true; - } else if (api != null && !api.endsWith("/bot")) { - accountConfig.fileApiUrl(api4FileUrlSet = api + "/file/bot"); - } - if (isCustomApi) { - logger.info(String.format(""" - Telegram Bot API set to : - - %s - - %s""", - apiUrlSet, api4FileUrlSet - )); - } - final TelegramBot account = accountConfig.build(); - logger.info("Trying to login..."); - for (int i = 1; i < 4; i++) { - if (i != 1) logger.info("retrying..."); - try { - final User remote = account.execute(new GetMe()).user(); - if (requireName != null && !requireName.equals(remote.username())) - throw new RuntimeException("Required the bot @" + requireName + " but @" + remote.username() + " logged in!"); - logger.info("Succeed login to @" + remote.username()); - return new LogInResult(account, remote.username(), remote.id()); - } catch (Exception e) { - logger.error(Log.exceptionLog(e)); - logger.error("login failed."); - } - } - throw new RuntimeException("Login failed.."); - } - - /** - * @see #saveDataAll() - * @since 0.4.3.0 - */ - public static void callSaveData () { - INSTANCE.saveDataAll(); - logger.info("done all save action."); - } - - /** - * 检查 Coeur 是否已经完成初始化. - * @since 1.0.0-alpha5 - */ - public static boolean available() { - return INSTANCE != null; - } - - /** - * 获取登录成功后的 telegram bot 对象 - * - * @return {@link #account MornyCoeur.account} - */ - @Nonnull - public static TelegramBot getAccount () { - return INSTANCE.account; - } - - /** - * 获取登录 bot 的 username - * - * @return {@link #username MornyCoeur.username} - */ - @Nonnull - public static String getUsername () { - return INSTANCE.username; - } - - /** - * 获取当前 morny 的配置数据 - * - * @return {@link #config MornyCoeur.config} - */ - @Nonnull - public static MornyConfig config () { - return INSTANCE.config; - } - - /** - * 获取 Morny 的{@link MornyTrusted 信任验证机} - * - * @return {@link #trusted MornyCoeur.trusted} - */ - @Nonnull - public static MornyTrusted trustedInstance () { - return INSTANCE.trusted; - } - - @Nonnull - public static MornyQueries queryManager () { - return INSTANCE.queryManager; - } - - @Nonnull - public static ExtraAction extra () { - return INSTANCE.extraActionInstance; - } - - public static long getUserid () { return INSTANCE.userid; } - - public static void exit (int status, Object reason) { - INSTANCE.whileExitReason = reason; - System.exit(status); - } - - public static Object getExitReason () { - return INSTANCE.whileExitReason; - } - -} diff --git a/src/main/old/cc/sukazyo/cono/morny/MornySystem.java b/src/main/old/cc/sukazyo/cono/morny/MornySystem.java deleted file mode 100644 index edd4719..0000000 --- a/src/main/old/cc/sukazyo/cono/morny/MornySystem.java +++ /dev/null @@ -1,145 +0,0 @@ -package cc.sukazyo.cono.morny; - -import cc.sukazyo.cono.morny.daemon.MornyReport; -import cc.sukazyo.cono.morny.internal.BuildConfigField; -import cc.sukazyo.cono.morny.util.FileUtils; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.io.IOException; -import java.net.URISyntaxException; -import java.security.NoSuchAlgorithmException; - -/** - * Morny Cono 的 Coeur 的程序属性存放类 - */ -public class MornySystem { - - /** - * 程序的语义化版本号. - *

- * 这个版本号包含了以下的 {@link #VERSION_BASE}, {@link #VERSION_DELTA} 字段, - * 但不包含作为附加属性的构建时的{@link BuildConfig#COMMIT git 状态}属性 - *

- * 这个格式的版本号也是在 maven 包仓库中所使用的版本号 - * @since 1.0.0-alpha4 - */ - @BuildConfigField @Nonnull public static final String VERSION = BuildConfig.VERSION; - /** - * 程序的完整语义化版本号. - *

- * 包含了全部的 {@link #VERSION_BASE}, {@link #VERSION_DELTA}, 以及{@link BuildConfig#COMMIT git 状态}属性。 - * 虽然仍旧不包含{@link #CODENAME}属性 - *

- * 这个格式的版本号也是 gradle 构建配置使用的版本号,也在普通打包时生成文件时使用 - * @since 1.0.0-alpha4.2 - */ - @BuildConfigField @Nonnull public static final String VERSION_FULL = BuildConfig.VERSION_FULL; - /** - * 程序的基础版本号. - *

- * 它只包含了版本号中的主要信息:例如 {@code 0.8.0.5}, {@code 1.0.0-alpha-3}, - * 而不会有用于精确定义的 {@link #VERSION_DELTA} 字段和作为附加使用的 {@link BuildConfig#COMMIT git commit 信息} - * @since 1.0.0-alpha4 - */ - @BuildConfigField @Nonnull public static final String VERSION_BASE = BuildConfig.VERSION_BASE; - /** - * 程序的版本 delta. - * —— 设计上用于在一个基版本当中分出不同构建的版本. - *

- * {@link null} 作为值,表示这个字段没有被使用. - *

- * 版本 delta 会以 {@code -δversion-delta} 的形式附着在 {@link #VERSION_BASE} 之后. - * 两者合并后的版本号格式即为 {@link #VERSION} - *

- * 在发行版本中一般不应该被使用. - *

- * 目前并不多被使用. - * @since 1.0.0-alpha4 - */ - @BuildConfigField @Nullable public static final String VERSION_DELTA = BuildConfig.VERSION_DELTA; - - /** - * Morny Coeur 当前的版本代号. - *

- * 一个单个单词,一般作为一个大版本的名称,只在重大更新改变
- * 格式保持为仅由小写字母和数字组成
- * 有时也可能是复合词或特殊的词句
- *
- */ - @BuildConfigField @Nonnull public static final String CODENAME = BuildConfig.CODENAME; - - /** - * Coeur 的代码仓库的链接. 它应该链接到当前程序的源码主页. - *

- * {@link null} 表示这个属性在构建时未被设置(或没有源码主页) - * @since 1.0.0-alpha4 - */ - @BuildConfigField @Nullable public static final String CODE_STORE = BuildConfig.CODE_STORE; - /** - * Coeur 的 git commit 链接. - *

- * 它应该是一个可以通过 {@link String#format(String, Object...)} 要求格式的链接模板,带有一个 {@link String} 类型的槽位 —— - * 通过 String.format(COMMIT_PATH, {@link BuildConfig#COMMIT}) 即可取得当前当前程序所基于的 commit 的链接。 - * @since 1.0.0-alpha4 - */ - @BuildConfigField @Nullable public static final String COMMIT_PATH = BuildConfig.COMMIT_PATH; - - /** @see #VERSION_DELTA */ - @BuildConfigField - public static boolean isUseDelta () { return VERSION_DELTA != null; } - - /** @see BuildConfig#COMMIT */ - @BuildConfigField - @SuppressWarnings("ConstantConditions") - public static boolean isGitBuild () { return BuildConfig.COMMIT != null; } - - /** @see BuildConfig#COMMIT */ - @BuildConfigField - public static boolean isCleanBuild () { return BuildConfig.CLEAN_BUILD; } - - /** - * 获取程序的当前构建所基于的 git commit 的链接. - *

- * 如果 {@link #COMMIT_PATH}(一般表示没有公开储存库) - * 或是 {@link BuildConfig#COMMIT}(一般表示程序的构建环境没有使用 git) - * 任何一个不可用,则此方法也不可用。 - * - * @return 当前构建的 git commit 链接,为空则表示不可用。 - * @see #COMMIT_PATH - * @since 1.0.0-alpha4 - */ - @Nullable - @BuildConfigField - @SuppressWarnings("ConstantConditions") - public static String currentCodePath () { - if (COMMIT_PATH == null || !isGitBuild()) return null; - return String.format(COMMIT_PATH, BuildConfig.COMMIT); - } - - - - /** - * 获取程序 jar 文件的 md5-hash 值
- *
- * 只支持 jar 文件方式启动的程序 —— - * 如果是通过 classpath 来启动,程序无法找到本体jar文件,则会返回 {@code } 文本 - *
- * 值格式为 {@link java.lang.String} - * - * @return 程序jar文件的 md5-hash 值字符串,或 {@code } 如果出现错误 - */ - @Nonnull - public static String getJarMd5() { - try { - return FileUtils.getMD5Three(MornyCoeur.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()); - } catch (IOException | URISyntaxException e) { - return ""; - } catch (NoSuchAlgorithmException e) { - Log.logger.error(Log.exceptionLog(e)); - MornyReport.exception(e, ""); - return ""; - } - } - -} diff --git a/src/main/old/cc/sukazyo/cono/morny/MornyTrusted.java b/src/main/old/cc/sukazyo/cono/morny/MornyTrusted.java deleted file mode 100644 index 7a43fa0..0000000 --- a/src/main/old/cc/sukazyo/cono/morny/MornyTrusted.java +++ /dev/null @@ -1,42 +0,0 @@ -package cc.sukazyo.cono.morny; - -import com.pengrad.telegrambot.model.ChatMember.Status; - -import java.util.Set; - -/** - * 对用户进行身份权限验证的管理类 - */ -public class MornyTrusted { - - private final MornyCoeur instance; - - public MornyTrusted (MornyCoeur instance) { - this.instance = instance; - } - - /** - * 用于检查一个 telegram-user 是否受信任
- *
- * 用户需要受信任才能执行一些对程序甚至是宿主环境而言危险的操作,例如关闭程序
- *
- * 它的逻辑(目前)是检查群聊 {@link MornyConfig#trustedChat} 中这个用户是否为群组管理员 - * - * @param userId 需要检查的用户的id - * @return 所传递的用户id对应的用户是否受信任 - */ - public boolean isTrusted (long userId) { - if (userId == instance.config.trustedMaster) return true; - if (instance.config.trustedChat == -1) return false; - return MornyCoeur.extra().isUserInGroup(userId, instance.config.trustedChat, Status.administrator); - } - - public boolean isTrustedForDinnerRead (long userId) { - return instance.config.dinnerTrustedReaders.contains(userId); - } - - public Set getTrustedReadersOfDinnerSet () { - return Set.copyOf(instance.config.dinnerTrustedReaders); - } - -} diff --git a/src/main/old/cc/sukazyo/cono/morny/bot/command/Roll.java b/src/main/old/cc/sukazyo/cono/morny/bot/command/Roll.java deleted file mode 100644 index c3c865f..0000000 --- a/src/main/old/cc/sukazyo/cono/morny/bot/command/Roll.java +++ /dev/null @@ -1,4 +0,0 @@ -package cc.sukazyo.cono.morny.bot.command; - -public class Roll { -} diff --git a/src/main/old/cc/sukazyo/cono/morny/bot/command/package-info.java b/src/main/old/cc/sukazyo/cono/morny/bot/command/package-info.java deleted file mode 100644 index a2d0379..0000000 --- a/src/main/old/cc/sukazyo/cono/morny/bot/command/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -/** - * 一系列的 telegram bot 命令的声明. - *

- * 命令将在 {@link cc.sukazyo.cono.morny.bot.command.MornyCommands} 当中实例化并注册管理,并通过事件 - * {@link cc.sukazyo.cono.morny.bot.event.OnTelegramCommand} 调用. - */ -package cc.sukazyo.cono.morny.bot.command; 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 deleted file mode 100644 index e099fb7..0000000 --- a/src/main/old/cc/sukazyo/cono/morny/bot/event/OnActivityRecord.java +++ /dev/null @@ -1,28 +0,0 @@ -package cc.sukazyo.cono.morny.bot.event; - -import cc.sukazyo.cono.morny.bot.api.EventListener; -import cc.sukazyo.cono.morny.daemon.TrackerDataManager; -import com.pengrad.telegrambot.model.Chat; -import com.pengrad.telegrambot.model.Update; - -import javax.annotation.Nonnull; - -@Deprecated -public class OnActivityRecord implements EventListener { - - @Override - public boolean onMessage (@Nonnull Update update) { - if ( - update.message().chat().type() == Chat.Type.supergroup || - update.message().chat().type() == Chat.Type.group - ) { - TrackerDataManager.record( - update.message().chat().id(), - update.message().from().id(), - (long)update.message().date() * 1000 - ); - } - return false; - } - -} 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 deleted file mode 100644 index 8af5bc5..0000000 --- a/src/main/old/cc/sukazyo/cono/morny/bot/event/OnKuohuanhuanNeedSleep.java +++ /dev/null @@ -1,39 +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.DeleteMessage; - -import javax.annotation.Nonnull; -import java.util.Calendar; -import java.util.GregorianCalendar; -import java.util.Locale; - -@Deprecated -public class OnKuohuanhuanNeedSleep implements EventListener { - - @Override - public boolean onMessage (@Nonnull Update update) { - final GregorianCalendar time = new GregorianCalendar(Locale.TAIWAN); - time.setTimeInMillis(System.currentTimeMillis()); - if ( - ( update.message().from().id() == 786563752L && ( - time.get(Calendar.HOUR_OF_DAY) >= 23 || - time.get(Calendar.HOUR_OF_DAY) < 5 - )) || ( update.message().from().id() == 1075871712L && ( - (time.get(Calendar.HOUR_OF_DAY) >= 22 && time.get(Calendar.MINUTE) >= 30) || - time.get(Calendar.HOUR_OF_DAY) >= 23 || - time.get(Calendar.HOUR_OF_DAY) < 5 - )) - ) { - MornyCoeur.extra().exec( - new DeleteMessage(update.message().chat().id(), - update.message().messageId()) - ); - return true; - } - return false; - } - -} 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 deleted file mode 100644 index 24c8c2b..0000000 --- a/src/main/old/cc/sukazyo/cono/morny/bot/event/OnRandomlyTriggered.java +++ /dev/null @@ -1,27 +0,0 @@ -package cc.sukazyo.cono.morny.bot.event; - -import cc.sukazyo.cono.morny.bot.api.EventListener; - -@Deprecated -public class OnRandomlyTriggered implements EventListener { - -// /** -// * function CODE_IK0XA1 -// */ -// // @Override -// public boolean onMessage (@Nonnull Update update) { -// -// if (update.message().text() == null) return false; -// -// if (update.message().text().contains("急") && Math.random()<(1d/20)) { -// MornyCoeur.extra().exec(new SendMessage( -// update.message().chat().id(), -// "急也没用" -// )); -// } -// -// return false; -// -// } - -} diff --git a/src/main/old/cc/sukazyo/cono/morny/daemon/MedicationTimer.java b/src/main/old/cc/sukazyo/cono/morny/daemon/MedicationTimer.java deleted file mode 100644 index 6760b4e..0000000 --- a/src/main/old/cc/sukazyo/cono/morny/daemon/MedicationTimer.java +++ /dev/null @@ -1,98 +0,0 @@ -package cc.sukazyo.cono.morny.daemon; - -import cc.sukazyo.cono.morny.MornyCoeur; -import cc.sukazyo.cono.morny.util.CommonFormat; -import com.pengrad.telegrambot.model.Message; -import com.pengrad.telegrambot.model.MessageEntity; -import com.pengrad.telegrambot.model.request.ParseMode; -import com.pengrad.telegrambot.request.EditMessageText; -import com.pengrad.telegrambot.request.SendMessage; -import com.pengrad.telegrambot.response.SendResponse; - -import java.time.LocalDateTime; -import java.time.ZoneOffset; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -import static cc.sukazyo.cono.morny.Log.exceptionLog; -import static cc.sukazyo.cono.morny.Log.logger; - -public class MedicationTimer extends Thread { - - private final ZoneOffset USE_TIME_ZONE = MornyCoeur.config().medicationTimerUseTimezone; - private final Set NOTIFY_AT_HOUR = MornyCoeur.config().medicationNotifyAt; - private final long NOTIFY_CHAT = MornyCoeur.config().medicationNotifyToChat; - public static final String NOTIFY_MESSAGE = "\uD83C\uDF65⏲"; - private static final String DAEMON_THREAD_NAME = "TIMER_Medication"; - - private static final long LAST_NOTIFY_ID_NULL = -1L; - private long lastNotify = LAST_NOTIFY_ID_NULL; - - public static class NoNotifyTimeTag extends Throwable { private NoNotifyTimeTag(){} } - - MedicationTimer () { - super(DAEMON_THREAD_NAME); - } - - @Override - public void run () { - logger.info("MedicationTimer started"); - while (!interrupted()) { - try { - waitToNextRoutine(); - sendNotification(); - } catch (InterruptedException e) { - interrupt(); - logger.info("MedicationTimer was interrupted, will be exit now"); - } catch (NoNotifyTimeTag ignored) { - logger.warn("Notify Time not Set and the MedicationTimer will not working!\nMedicationTimer will be exit now."); - interrupt(); - } catch (Exception e) { - logger.error("Unexpected error occurred"); - logger.error(exceptionLog(e)); - MornyReport.exception(e); - } - } - logger.info("MedicationTimer stopped"); - } - - private void sendNotification () { - final SendResponse resp = MornyCoeur.extra().exec(new SendMessage(NOTIFY_CHAT, NOTIFY_MESSAGE)); - if (resp.isOk()) lastNotify = resp.message().messageId(); - else lastNotify = LAST_NOTIFY_ID_NULL; - } - - public void refreshNotificationWrite (Message edited) { - if (edited.messageId() != lastNotify) return; - final String editTime = CommonFormat.formatDate(edited.editDate()*1000, 8); - ArrayList entities = new ArrayList<>(); - if (edited.entities() != null) entities.addAll(List.of(edited.entities())); - entities.add(new MessageEntity(MessageEntity.Type.italic, edited.text().length() + "\n-- ".length(), editTime.length())); - EditMessageText sending = new EditMessageText( - NOTIFY_CHAT, - edited.messageId(), - edited.text() + "\n-- " + editTime + " --" - ).parseMode(ParseMode.HTML).entities(entities.toArray(MessageEntity[]::new)); - MornyCoeur.extra().exec(sending); - lastNotify = LAST_NOTIFY_ID_NULL; - } - - public static long calcNextRoutineTimestamp (long baseTimeMillis, ZoneOffset useTimeZone, Set atHours) - throws NoNotifyTimeTag { - if (atHours.isEmpty()) throw new NoNotifyTimeTag(); - LocalDateTime time = LocalDateTime.ofEpochSecond( - baseTimeMillis/1000, (int)(baseTimeMillis%1000)*1000*1000, - useTimeZone - ).withMinute(0).withSecond(0).withNano(0); - do { - time = time.plusHours(1); - } while (!atHours.contains(time.getHour())); - return time.withMinute(0).withSecond(0).withNano(0).toInstant(useTimeZone).toEpochMilli(); - } - - private void waitToNextRoutine () throws InterruptedException, NoNotifyTimeTag { - sleep(calcNextRoutineTimestamp(System.currentTimeMillis(), USE_TIME_ZONE, NOTIFY_AT_HOUR) - System.currentTimeMillis()); - } - -} diff --git a/src/main/old/cc/sukazyo/cono/morny/daemon/MornyDaemons.java b/src/main/old/cc/sukazyo/cono/morny/daemon/MornyDaemons.java deleted file mode 100644 index 710a07a..0000000 --- a/src/main/old/cc/sukazyo/cono/morny/daemon/MornyDaemons.java +++ /dev/null @@ -1,34 +0,0 @@ -package cc.sukazyo.cono.morny.daemon; - -import cc.sukazyo.cono.morny.MornyCoeur; - -import static cc.sukazyo.cono.morny.Log.logger; - -public class MornyDaemons { - - public static final MedicationTimer medicationTimerInstance = new MedicationTimer(); - - public static void start () { - logger.info("ALL Morny Daemons starting..."); -// TrackerDataManager.init(); - medicationTimerInstance.start(); - MornyReport.onMornyLogIn(); - logger.info("Morny Daemons started."); - } - - public static void stop () { - - logger.info("ALL Morny Daemons stopping..."); - -// TrackerDataManager.DAEMON.interrupt(); - medicationTimerInstance.interrupt(); - -// TrackerDataManager.trackingLock.lock(); - try { medicationTimerInstance.join(); } catch (InterruptedException e) { e.printStackTrace(System.out); } - - MornyReport.onMornyExit(MornyCoeur.getExitReason()); - logger.info("ALL Morny Daemons STOPPED."); - - } - -} diff --git a/src/main/old/cc/sukazyo/cono/morny/daemon/MornyReport.java b/src/main/old/cc/sukazyo/cono/morny/daemon/MornyReport.java deleted file mode 100644 index 8f49964..0000000 --- a/src/main/old/cc/sukazyo/cono/morny/daemon/MornyReport.java +++ /dev/null @@ -1,159 +0,0 @@ -package cc.sukazyo.cono.morny.daemon; - -import cc.sukazyo.cono.morny.*; -import cc.sukazyo.cono.morny.bot.command.MornyInformation; -import cc.sukazyo.cono.morny.util.tgapi.event.EventRuntimeException; -import cc.sukazyo.cono.morny.util.tgapi.formatting.TGToString; -import com.google.gson.GsonBuilder; -import com.pengrad.telegrambot.model.User; -import com.pengrad.telegrambot.model.request.ParseMode; -import com.pengrad.telegrambot.request.BaseRequest; -import com.pengrad.telegrambot.request.SendMessage; -import com.pengrad.telegrambot.response.BaseResponse; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import java.lang.reflect.Field; - -import static cc.sukazyo.cono.morny.Log.logger; -import static cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml; - -public class MornyReport { - - private static boolean unsupported () { - return !MornyCoeur.available() || MornyCoeur.config().reportToChat == -1; - } - - private static , R extends BaseResponse> void executeReport (@Nonnull T report) { - if (unsupported()) return; - try { - MornyCoeur.extra().exec(report); - } catch (EventRuntimeException.ActionFailed e) { - logger.warn("cannot execute report to telegram:"); - logger.warn(Log.exceptionLog(e).indent(4)); - logger.warn("tg-api response:"); - logger.warn(e.getResponse().toString().indent(4)); - } - } - - public static void exception (@Nonnull Throwable e, @Nullable String description) { - if (unsupported()) return; - executeReport(new SendMessage( - MornyCoeur.config().reportToChat, - String.format(""" - ▌Coeur Unexpected Exception - %s -

%s
%s - """, - description == null ? "" : escapeHtml(description)+"\n", - escapeHtml(Log.exceptionLog(e)), - e instanceof EventRuntimeException.ActionFailed ? (String.format( - "\n\ntg-api error:\n
%s
", - new GsonBuilder().setPrettyPrinting().create().toJson(((EventRuntimeException.ActionFailed)e).getResponse())) - ) : "" - ) - ).parseMode(ParseMode.HTML)); - } - - public static void exception (@Nonnull Exception e) { exception(e, null); } - - public static void unauthenticatedAction (@Nonnull String action, @Nonnull User user) { - if (unsupported()) return; - executeReport(new SendMessage( - MornyCoeur.config().reportToChat, - String.format(""" - ▌User unauthenticated action - action: %s - by user %s - """, - escapeHtml(action), - TGToString.as(user).fullnameRefHtml() - ) - ).parseMode(ParseMode.HTML)); - } - - /** - * morny 登陆时的报告发送,包含已登录的账号 id 以及启动配置。 - * @since 1.0.0-alpha6 - */ - static void onMornyLogIn () { - executeReport(new SendMessage( - MornyCoeur.config().reportToChat, - String.format(""" - ▌Morny Logged in - -v %s - as user @%s - - as config fields: - %s - """, - MornyInformation.getVersionAllFullTagHTML(), - MornyCoeur.getUsername(), - sectionConfigFields(MornyCoeur.config()) - ) - ).parseMode(ParseMode.HTML)); - } - - /** - * 返回一个 config 字段与值的列表,可以作为 telegram html 格式输出 - * @since 1.0.0-alpha6 - */ - private static String sectionConfigFields (@Nonnull MornyConfig config) { - final StringBuilder echo = new StringBuilder(); - for (Field field : config.getClass().getFields()) { - echo.append("- ").append(field.getName()).append(" "); - try { - if (field.isAnnotationPresent(MornyConfig.Sensitive.class)) { - echo.append(": sensitive_field"); - } else { - final Object fieldValue = field.get(config); - echo.append("= "); - if (fieldValue == null) - echo.append("null"); - else echo.append("").append(escapeHtml(fieldValue.toString())).append(""); - } - } catch (IllegalAccessException | IllegalArgumentException | NullPointerException e) { - echo.append(": ").append(escapeHtml("")).append(""); - logger.error("error while reading config field " + field.getName()); - logger.error(Log.exceptionLog(e)); - exception(e, "error while reading config field " + field.getName()); - } - echo.append("\n"); - } - return echo.substring(0, echo.length()-1); - } - - /** - * morny 关闭/登出时发送的报告. - *

- * 基于 java 的程序关闭钩子,因此仍然无法在意外宕机的情况下发送报告. - * @param causedBy - * 关闭的原因。 - * 可以使用 {@link User Telegram 用户对象} 表示由一个用户执行了关闭, - * 传入其它数据将使用 {@code #toString} 输出其内容。 - * 传入 {@link null} 则表示不表明原因。 - */ - static void onMornyExit (@Nullable Object causedBy) { - if (unsupported()) return; - String causedTag = null; - if (causedBy != null) { - if (causedBy instanceof User) - causedTag = TGToString.as((User)causedBy).fullnameRefHtml(); - else - causedTag = "" + escapeHtml(causedBy.toString()) + ""; - } - executeReport(new SendMessage( - MornyCoeur.config().reportToChat, - String.format(""" - ▌Morny Exited - from user @%s - %s - """, - MornyCoeur.getUsername(), - causedBy == null ? "with UNKNOWN reason" : "\nby " + causedTag - ) - ).parseMode(ParseMode.HTML)); - } - -} diff --git a/src/main/old/cc/sukazyo/cono/morny/daemon/TrackerDataManager.java b/src/main/old/cc/sukazyo/cono/morny/daemon/TrackerDataManager.java deleted file mode 100644 index f8a99fc..0000000 --- a/src/main/old/cc/sukazyo/cono/morny/daemon/TrackerDataManager.java +++ /dev/null @@ -1,174 +0,0 @@ -package cc.sukazyo.cono.morny.daemon; - -import java.io.File; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; -import java.nio.charset.StandardCharsets; -import java.nio.file.StandardOpenOption; -import java.util.HashMap; -import java.util.TreeSet; -import java.util.concurrent.locks.ReentrantLock; - -import static cc.sukazyo.cono.morny.Log.exceptionLog; -import static cc.sukazyo.cono.morny.Log.logger; - -public class TrackerDataManager { - - /** {@link TrackerDaemon} 的锁。保证在程序中只有一个 TrackerDaemon 会运行。 */ - public static final ReentrantLock trackingLock = new ReentrantLock(); - /** {@link #record Tracker 缓存}的锁

为保证对 Tracker 缓存的操作不会造成线程冲突,在操作缓存数据前应先取得此锁。 */ - private static final ReentrantLock recordLock = new ReentrantLock(); - /** Tracker 数据的内存缓存

进行数据操作前请先取得对应的{@link #recordLock 锁} */ - private static HashMap>> record = new HashMap<>(); - - public static final TrackerDaemon DAEMON = new TrackerDaemon(); - public static class TrackerDaemon extends Thread { - - public TrackerDaemon () { this.setName("TRACKER"); } - - @Override - public void run () { - trackingLock.lock(); - logger.info("Tracker started."); - long lastWaitTimestamp = System.currentTimeMillis(); - boolean postProcess = false; - do { - lastWaitTimestamp += 10 * 60 * 1000; - long sleeping = lastWaitTimestamp - System.currentTimeMillis(); - if (sleeping > 0) { - try { Thread.sleep(sleeping); } catch (InterruptedException e) { interrupt(); } - } else { - logger.warn("Tracker may be too busy to process data!!"); - lastWaitTimestamp = System.currentTimeMillis(); - } - if (interrupted()) { - postProcess = true; - logger.info("CALLED TO EXIT! writing cache."); - } - if (record.size() != 0) { - save(); - } - else logger.info("nothing to do yet"); - } while (!postProcess); - trackingLock.unlock(); - logger.info("Tracker exited."); - } - - } - - /** - * 向 Tracker 缓存写入一条 tracker 数据. - *

- * 这个方法对于 Tracker 缓存是原子化的。 - * - * @param chat tracker 所属的 Telegram Chat ID - * @param user tracker 所记录的 Telegram User ID - * @param timestamp tracker 被生成时的 UTC 时间戳 - */ - public static void record (long chat, long user, long timestamp) { - recordLock.lock(); - if (!record.containsKey(chat)) record.put(chat, new HashMap<>()); - HashMap> chatUsers = record.get(chat); - if (!chatUsers.containsKey(user)) chatUsers.put(user, new TreeSet<>()); - TreeSet userRecords = chatUsers.get(user); - userRecords.add(timestamp); - recordLock.unlock(); - } - - /** - * 开启 {@link TrackerDaemon}. - *

- * 由于 Tracker 已废弃,这个方法已无作用。 - */ - @SuppressWarnings("unused") - public static void init () { - DAEMON.start(); - } - - /** - * 执行 Tracker 的保存逻辑. - * @see #reset() 弹出 Tracker 缓存 - * @see #save(HashMap) 执行硬盘写入操作 - */ - public static void save () { - logger.info("start writing tracker data."); - save(reset()); - logger.info("done writing tracker data."); - } - - /** - * 将 Tracker 的缓存数据弹出. - *

- * 这个方法将返回现在 Tracker 的所有缓存数据,然后清除缓存。 - *

- * 这个方法对于 Tracker 缓存是原子化的。 - * - * @return 当前 Tracker 所包含的内容 - */ - private static HashMap>> reset () { - recordLock.lock(); - HashMap>> recordOld = record; - record = new HashMap<>(); - recordLock.unlock(); - return recordOld; - } - - /** - * 将 Tracker 数据写入到硬盘. - * - * @param record 需要保存的 Tracker 数据集 - */ - private static void save (HashMap>> record) { - - { - if (!record.containsKey(0L)) record.put(0L, new HashMap<>()); - HashMap> chatUsers = record.get(0L); - if (!chatUsers.containsKey(0L)) chatUsers.put(0L, new TreeSet<>()); - TreeSet userRecords = chatUsers.get(0L); - userRecords.add(System.currentTimeMillis()); - } - - record.forEach((chat, chatUsers) -> chatUsers.forEach((user, userRecords) -> { - - long dayCurrent = -1; - FileChannel channelCurrent = null; - - for (long timestamp : userRecords) { - try { - - long day = timestamp / (24 * 60 * 60 * 1000); - if (dayCurrent != day) { - if (channelCurrent != null) channelCurrent.close(); - channelCurrent = openFile(chat, user, day); - dayCurrent = day; - } - - assert channelCurrent != null; - final int result = channelCurrent.write(ByteBuffer.wrap( - String.format("%d\n", timestamp).getBytes(StandardCharsets.UTF_8) - )); - - if (result == 0) logger.warn("writing tracker data %d/%d/%d: write only 0 bytes! is anything wrong?"); - - } catch (Exception e) { - final String message = String.format("exception in write tracker data: %d/%d/%d", chat, user, timestamp); - logger.error(message); - logger.error(exceptionLog(e)); - MornyReport.exception(e, message); - } - } - - })); - - } - - private static FileChannel openFile (long chat, long user, long day) throws IOException { - File data = new File(String.format("./data/tracker/%d/%d", chat, user)); - if (!data.isDirectory()) if (!data.mkdirs()) throw new IOException("Cannot create file directory " + data.getPath()); - File file = new File(data, String.valueOf(day)); - if (!file.isFile()) if (!file.createNewFile()) throw new IOException("Cannot create file " + file.getPath()); - return FileChannel.open(file.toPath(), StandardOpenOption.APPEND); - } - -} diff --git a/src/main/old/cc/sukazyo/cono/morny/data/TelegramImages.java b/src/main/old/cc/sukazyo/cono/morny/data/TelegramImages.java deleted file mode 100644 index f433c65..0000000 --- a/src/main/old/cc/sukazyo/cono/morny/data/TelegramImages.java +++ /dev/null @@ -1,81 +0,0 @@ -package cc.sukazyo.cono.morny.data; - -import cc.sukazyo.cono.morny.MornyAssets; -import cc.sukazyo.cono.morny.daemon.MornyReport; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.io.IOException; -import java.io.InputStream; - -import static cc.sukazyo.cono.morny.Log.exceptionLog; -import static cc.sukazyo.cono.morny.Log.logger; - -/** - * The images of morny will use. - * - * @since 1.0.0-RC4 - */ -public class TelegramImages { - - /** - * Image that stored in the {@link MornyAssets#pack}. - *

- * It has a final {@link #assetsPath} record that is its store location, - * and has a {@link #cache} of the binary data. - * - * @since 1.0.0-RC4 - */ - public static class AssetsFileImage { - - /** the path where the image is stored in {@link MornyAssets#pack}. */ - @Nonnull private final String assetsPath; - /** the binary data cache of the image.

{@link null} means it hasn't been cached. */ - @Nullable private byte[] cache = null; - - /** - * An {@link AssetsFileImage}. - * - * @param path the image path relative to {@link MornyAssets#pack}'s root. - */ - AssetsFileImage (@Nonnull String path) { - this.assetsPath = path; - } - - /** - * Get the binary data. - *

- * Will read the {@link #cache} firstly. If read {@link null}, - * then it will try {@link #read load the file}, and read again. - * - * @return The binary data of the image. - * @throws IllegalStateException While the {@link #read()} failed to read data and - * the result {@link #cache} is still null - */ - @Nonnull public byte[] get() { - if (cache == null) read(); - if (cache == null) throw new IllegalStateException("Failed get assets file image."); - return cache; - } - - /** - * Load the file from {@link MornyAssets#pack}, and stored the binary data to {@link #cache}. - *

- * If failed, it will output the exception to the log and the {@link MornyReport}, - * and remains the cache's current data. - */ - private void read() { - try (InputStream stream = MornyAssets.pack.getResource(assetsPath).read()) { - this.cache = stream.readAllBytes(); - } catch (IOException e) { - logger.error("Cannot read resource file"); - logger.error(exceptionLog(e)); - MornyReport.exception(e, "Cannot read resource file"); - } - } - - } - - public static final AssetsFileImage IMG_ABOUT = new AssetsFileImage("images/featured-image@0.5x.jpg"); - -} diff --git a/src/main/old/cc/sukazyo/cono/morny/data/TelegramStickers.java b/src/main/old/cc/sukazyo/cono/morny/data/TelegramStickers.java deleted file mode 100644 index d23d1fe..0000000 --- a/src/main/old/cc/sukazyo/cono/morny/data/TelegramStickers.java +++ /dev/null @@ -1,87 +0,0 @@ -package cc.sukazyo.cono.morny.data; - -import cc.sukazyo.cono.morny.util.tgapi.ExtraAction; -import com.pengrad.telegrambot.request.SendMessage; -import com.pengrad.telegrambot.request.SendSticker; -import com.pengrad.telegrambot.response.SendResponse; - -import javax.annotation.Nonnull; -import java.lang.reflect.Field; - -/** - * 存放 bot 使用到的贴纸 - * @since 0.4.2.0 - */ -public class TelegramStickers { - - public static final String ID_ONLINE_STATUS_RETURN = "CAACAgEAAx0CW-CvvgAC5eBhhhODGRuu0pxKLwoQ3yMsowjviAACcycAAnj8xgVVU666si1utiIE"; - public static final String ID_HELLO = "CAACAgEAAxkBAAMnYYYWKNXO4ibo9dlsmDctHhhV6fIAAqooAAJ4_MYFJJhrHS74xUAiBA"; - public static final String ID_EXIT = "CAACAgEAAxkBAAMoYYYWt8UjvP0N405SAyvg2SQZmokAAkMiAAJ4_MYFw6yZLu06b-MiBA"; - public static final String ID_403 = "CAACAgEAAxkBAAMqYYYa_7hpXH6hMOYMX4Nh8AVYd74AAnQnAAJ4_MYFRdmmsQKLDZgiBA"; - public static final String ID_404 = "CAACAgEAAx0CSQh32gABA966YbRJpbmi2lCHINBDuo1DknSTsbsAAqUoAAJ4_MYFUa8SIaZriAojBA"; - public static final String ID_WAITING = "CAACAgEAAx0CSQh32gABA-8DYbh7W2VhJ490ucfZMUMrgMR2FW4AAm4nAAJ4_MYFjx6zpxJPWsQjBA"; - public static final String ID_SENT = "CAACAgEAAx0CSQh32gABA--zYbiyU_wOijEitp-0tSl_k7W6l3gAAgMmAAJ4_MYF4GrompjXPx4jBA"; - public static final String ID_SAVED = "CAACAgEAAx0CSQh32gABBExuYdB_G0srfhQldRWkBYxWzCOv4-IAApooAAJ4_MYFcjuNZszfQcQjBA"; - public static final String ID_PROGYNOVA = "CAACAgUAAxkBAAICm2KEuL7UQqNP7vSPCg2DHJIND6UsAAKLAwACH4WSBszIo722aQ3jJAQ"; - public static final String ID_NETWORK_ERR = "CAACAgEAAxkBAAID0WNJgNEkD726KW4vZeFlw0FlVVyNAAIXJgACePzGBb50o7O1RbxoKgQ"; - - /** - * 向 telegram 输出当前的 {@link TelegramStickers} 中的所有 stickers. - * @param actionObject 要使用的 telegram account 包装实例 - * @param sentChat 目标 telegram chat id - * @param replyToMessageId 输出时回复指定的消息的 id。使用 {@link -1} 表示不回复消息 - * @since 0.8.0.6 - */ - public static void echoAllStickers (@Nonnull ExtraAction actionObject, long sentChat, int replyToMessageId) { - - for (Field object : TelegramStickers.class.getFields()) { - if (object.getType()==String.class && object.getName().startsWith("ID_")) { - try { - - final String stickerId = (String)object.get(""); - SendSticker echo = new SendSticker(sentChat, stickerId); - SendMessage echoName = new SendMessage(sentChat, object.getName()); - if (replyToMessageId!=-1) echo.replyToMessageId(replyToMessageId); - SendResponse echoedName = actionObject.exec(echoName); - actionObject.exec(echo.replyToMessageId(echoedName.message().messageId())); - - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } - } - - } - - /** - * 向 telegram 输出当前的 {@link TelegramStickers} 中的某个特定 sticker. - * @param stickerFieldID 要输出的 sticker 在 {@link TelegramStickers} 当中的字段名 - * @param actionObject 要使用的 telegram account 包装实例 - * @param sentChat 目标 telegram chat id - * @param replyToMessageId 输出时回复指定的消息的 id。使用 {@link -1} 表示不回复消息 - * @since 0.8.0.6 - */ - public static void echoStickerByID ( - @Nonnull String stickerFieldID, - @Nonnull ExtraAction actionObject, long sentChat, int replyToMessageId - ) { - try { - // normally get the sticker and echo - Field sticker = TelegramStickers.class.getField(stickerFieldID); - SendMessage echoName = new SendMessage(sentChat, sticker.getName()); - SendSticker echo = new SendSticker(sentChat, (String)sticker.get("")); - if (replyToMessageId!=-1) echo.replyToMessageId(replyToMessageId); - SendResponse echoedName = actionObject.exec(echoName); - actionObject.exec(echo.replyToMessageId(echoedName.message().messageId())); - } catch (NoSuchFieldException e) { - // no such sticker found - SendSticker echo404 = new SendSticker(sentChat, TelegramStickers.ID_404); - if (replyToMessageId!=-1) echo404.replyToMessageId(replyToMessageId); - actionObject.exec(echo404); - } catch (IllegalAccessException e) { - // java-reflect get sticker FILE_ID failed - throw new RuntimeException(e); - } - } - -} diff --git a/src/main/scala/cc/sukazyo/cono/morny/Log.scala b/src/main/scala/cc/sukazyo/cono/morny/Log.scala new file mode 100644 index 0000000..5ca1a38 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/Log.scala @@ -0,0 +1,29 @@ +package cc.sukazyo.cono.morny + +import cc.sukazyo.messiva.logger.Logger +import cc.sukazyo.messiva.appender.ConsoleAppender +import cc.sukazyo.messiva.formatter.SimpleFormatter +import cc.sukazyo.messiva.log.LogLevel + +import java.io.{PrintWriter, StringWriter} + +object Log { + + val logger: Logger = Logger( + ConsoleAppender( + SimpleFormatter() + ) + ).minLevel(LogLevel.INFO) + + def debug: Boolean = logger.levelSetting.minLevel.level <= LogLevel.DEBUG.level + + def debug(is: Boolean): Unit = + if is then logger.minLevel(LogLevel.ALL) + else logger.minLevel(LogLevel.INFO) + + def exceptionLog (e: Throwable): String = + val stackTrace = StringWriter() + e printStackTrace PrintWriter(stackTrace) + stackTrace toString + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/MornyAbout.scala b/src/main/scala/cc/sukazyo/cono/morny/MornyAbout.scala new file mode 100644 index 0000000..9d608ed --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/MornyAbout.scala @@ -0,0 +1,17 @@ +package cc.sukazyo.cono.morny + +import java.io.IOException + +object MornyAbout { + + val MORNY_PREVIEW_IMAGE_ASCII: String = + try { MornyAssets.pack getResource "texts/server-hello.txt" readAsString } + catch case e: IOException => + throw RuntimeException("Cannot read MORNY_PREVIEW_IMAGE_ASCII from assets pack", e) + + val MORNY_SOURCECODE_LINK = "https://github.com/Eyre-S/Coeur-Morny-Cono" + val MORNY_SOURCECODE_SELF_HOSTED_MIRROR_LINK = "https://storage.sukazyo.cc/Eyre_S/Coeur-Morny-Cono" + val MORNY_ISSUE_TRACKER_LINK = "https://github.com/Eyre-S/Coeur-Morny-Cono/issues" + val MORNY_USER_GUIDE_LINK = "https://book.sukazyo.cc/morny" + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/MornyAssets.scala b/src/main/scala/cc/sukazyo/cono/morny/MornyAssets.scala new file mode 100644 index 0000000..489ac36 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/MornyAssets.scala @@ -0,0 +1,9 @@ +package cc.sukazyo.cono.morny + +import cc.sukazyo.restools.ResourcesPackage + +object MornyAssets { + + val pack: ResourcesPackage = ResourcesPackage(MornyAssets.getClass, "assets_morny") + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/MornyCoeur.scala b/src/main/scala/cc/sukazyo/cono/morny/MornyCoeur.scala new file mode 100644 index 0000000..6bfad74 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/MornyCoeur.scala @@ -0,0 +1,149 @@ +package cc.sukazyo.cono.morny + +import cc.sukazyo.cono.morny.bot.command.MornyCommands +import cc.sukazyo.cono.morny.daemon.MornyDaemons +import cc.sukazyo.cono.morny.util.tgapi.ExtraAction +import cc.sukazyo.cono.morny.Log.{exceptionLog, logger} +import cc.sukazyo.cono.morny.MornyCoeur.THREAD_MORNY_EXIT +import cc.sukazyo.cono.morny.bot.api.TelegramUpdatesListener +import cc.sukazyo.cono.morny.bot.event.MornyEventListeners +import com.pengrad.telegrambot.TelegramBot +import com.pengrad.telegrambot.request.GetMe + +import scala.util.boundary +import scala.util.boundary.break + +object MornyCoeur { + + val THREAD_MORNY_EXIT = "morny-exiting" + + private var INSTANCE: MornyCoeur|Null = _ + + val coeurStartTimestamp: Long = ServerMain.systemStartupTime + + def account: TelegramBot = INSTANCE.account + def username: String = INSTANCE.username + def userid: Long = INSTANCE.userid + def config: MornyConfig = INSTANCE.my_config + def trusted: MornyTrusted = INSTANCE.trusted + def extra: ExtraAction = INSTANCE.extra + + def available: Boolean = INSTANCE != null + def callSaveData(): Unit = INSTANCE.saveDataAll() + + def exitReason: AnyRef|Null = INSTANCE.whileExit_reason + + def exit (status: Int, reason: AnyRef): Unit = + INSTANCE.whileExit_reason = reason + System exit status + + def init (using config: MornyConfig): Unit = { + + if (INSTANCE ne null) + logger error "Coeur already started!!!" + return; + + logger info "Coeur starting..." + INSTANCE = MornyCoeur() + + MornyDaemons.start() + + logger info "start telegram event listening" + MornyEventListeners.registerAllEvents() + INSTANCE.account.setUpdatesListener(TelegramUpdatesListener) + + if config.commandLoginRefresh then + logger info "resetting telegram command list" + MornyCommands.automaticTGListUpdate() + + logger info "Coeur start complete." + + } + +} + +class MornyCoeur (using config: MornyConfig) { + def my_config: MornyConfig = config + + logger info s"args key:\n ${config.telegramBotKey}" + if config.telegramBotUsername ne null then + logger info s"login as:\n ${config.telegramBotUsername}" + + private val __loginResult = login() + if (__loginResult eq null) + logger error "Login to bot failed." + System exit -1 + + configure_exitCleanup() + + val account: TelegramBot = __loginResult.account + val username: String = __loginResult.username + val userid: Long = __loginResult.userid + + val trusted: MornyTrusted = MornyTrusted(using this) + val extra: ExtraAction = ExtraAction as __loginResult.account + var whileExit_reason: AnyRef|Null = _ + + def saveDataAll(): Unit = { + // nothing to do + logger info "done all save action." + } + + private def exitCleanup (): Unit = { + MornyDaemons.stop() + if config.commandLogoutClear then + MornyCommands.automaticTGListRemove() + } + + private def configure_exitCleanup (): Unit = { + Runtime.getRuntime.addShutdownHook(new Thread(() => exitCleanup(), THREAD_MORNY_EXIT)) + } + + private case class LoginResult(account: TelegramBot, username: String, userid: Long) + + private def login (): LoginResult|Null = { + + val builder = TelegramBot.Builder(config.telegramBotKey) + var api_bot = config.telegramBotApiServer + var api_file = config.telegramBotApiServer4File + if (api_bot ne null) + if api_bot endsWith "/" then api_bot = api_bot dropRight 1 + if !(api_bot endsWith "/bot") then api_bot += "/bot" + builder.apiUrl(api_bot) + if (api_file ne null) + if api_file endsWith "/file/" then api_file = api_file dropRight 1 + if !(api_file endsWith "/file/bot") then api_file += "/file/bot" + builder.apiUrl(api_bot) + if ((api_bot ne null) || (api_file ne null)) + logger info + s"""Telegram bot api set to: + |- bot: $api_bot + |- file: $api_file""" + .stripMargin + + val account = builder build + + logger info "Trying to login..." + boundary[LoginResult|Null] { + for (i <- 0 to 3) { + if i > 0 then logger info "retrying..." + try { + val remote = (account execute GetMe()).user + if ((config.telegramBotUsername ne null) && config.telegramBotUsername != remote.username) + throw RuntimeException(s"Required the bot @${config.telegramBotUsername} but @${remote.username} logged in") + logger info s"Succeed logged in to @${remote.username}" + break(LoginResult(account, remote.username, remote.id)) + } catch + case r: boundary.Break[LoginResult|Null] => throw r + case e => + logger error + s"""${exceptionLog(e)} + |login failed""" + .stripMargin + } + null + } + + } + +} diff --git a/src/main/old/cc/sukazyo/cono/morny/MornyConfig.java b/src/main/scala/cc/sukazyo/cono/morny/MornyConfig.java similarity index 97% rename from src/main/old/cc/sukazyo/cono/morny/MornyConfig.java rename to src/main/scala/cc/sukazyo/cono/morny/MornyConfig.java index a3d9907..2702a61 100644 --- a/src/main/old/cc/sukazyo/cono/morny/MornyConfig.java +++ b/src/main/scala/cc/sukazyo/cono/morny/MornyConfig.java @@ -129,7 +129,7 @@ public class MornyConfig { * End Configs | ConfigBuilder * * ======================================= */ - public MornyConfig (@Nonnull Prototype prototype) throws CheckFailure { + private MornyConfig (@Nonnull Prototype prototype) throws CheckFailure { this.telegramBotApiServer = prototype.telegramBotApiServer; this.telegramBotApiServer4File = prototype.telegramBotApiServer4File; if (prototype.telegramBotKey == null) throw new CheckFailure.NullTelegramBotKey(); @@ -159,6 +159,10 @@ public class MornyConfig { public static class Prototype { + public MornyConfig build () { + return new MornyConfig(this); + } + @Nullable public String telegramBotApiServer = null; @Nullable public String telegramBotApiServer4File = null; @Nullable public String telegramBotKey = null; diff --git a/src/main/scala/cc/sukazyo/cono/morny/MornySystem.scala b/src/main/scala/cc/sukazyo/cono/morny/MornySystem.scala new file mode 100644 index 0000000..69fb74f --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/MornySystem.scala @@ -0,0 +1,48 @@ +package cc.sukazyo.cono.morny + +import cc.sukazyo.cono.morny.internal.BuildConfigField +import cc.sukazyo.cono.morny.util.FileUtils + +import java.io.IOException +import java.net.URISyntaxException +import java.security.NoSuchAlgorithmException +import Log.{exceptionLog, logger} +import cc.sukazyo.cono.morny.daemon.MornyReport + +object MornySystem { + + @BuildConfigField val VERSION: String = BuildConfig.VERSION + @BuildConfigField val VERSION_FULL: String = BuildConfig.VERSION_FULL + @BuildConfigField val VERSION_BASE: String = BuildConfig.VERSION_BASE + @BuildConfigField val VERSION_DELTA: String = BuildConfig.VERSION_DELTA + @BuildConfigField val CODENAME: String = BuildConfig.CODENAME + @BuildConfigField val CODE_STORE: String = BuildConfig.CODE_STORE + @BuildConfigField val COMMIT_PATH: String = BuildConfig.COMMIT_PATH + + @BuildConfigField + def isUseDelta: Boolean = VERSION_DELTA ne null + + @BuildConfigField + def isGitBuild: Boolean = BuildConfig.COMMIT ne null + + @BuildConfigField + def isCleanBuild: Boolean = BuildConfig.CLEAN_BUILD + + def currentCodePath: String|Null = + if ((COMMIT_PATH eq null) || (!isGitBuild)) null + else COMMIT_PATH.formatted(BuildConfig.COMMIT) + + def getJarMD5: String = { + try { + FileUtils.getMD5Three(MornySystem.getClass.getProtectionDomain.getCodeSource.getLocation.toURI.getPath) + } catch + //noinspection ScalaUnnecessaryParentheses + case _: (IOException|URISyntaxException) => + "" + case n: NoSuchAlgorithmException => + logger error exceptionLog(n) + MornyReport.exception(n, "") + "" + } + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/MornyTrusted.scala b/src/main/scala/cc/sukazyo/cono/morny/MornyTrusted.scala new file mode 100644 index 0000000..d042e80 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/MornyTrusted.scala @@ -0,0 +1,16 @@ +package cc.sukazyo.cono.morny + +import com.pengrad.telegrambot.model.ChatMember.Status + +class MornyTrusted (using coeur: MornyCoeur)(using config: MornyConfig) { + + def isTrusted (userId: Long): Boolean = + if userId == config.trustedMaster then true + else if config.trustedChat == -1 then false + else coeur.extra isUserInGroup(userId, config.trustedChat, Status.administrator) + + def isTrusted_dinnerReader (userId: Long): Boolean = + if userId == config.trustedMaster then true + else config.dinnerTrustedReaders contains userId + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/ServerMain.scala b/src/main/scala/cc/sukazyo/cono/morny/ServerMain.scala index 91907ae..b481eb0 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/ServerMain.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/ServerMain.scala @@ -109,7 +109,7 @@ object ServerMain { | Morny ${MornySystem.CODENAME toUpperCase} | ${MornySystem.VERSION_BASE}${if (MornySystem.isUseDelta) "-δ"+MornySystem.VERSION_DELTA else ""} |- md5hash : - | ${MornySystem.getJarMd5} + | ${MornySystem.getJarMD5} |- gitstat : |${ if (MornySystem.isGitBuild) { s""" on commit ${if (MornySystem.isCleanBuild) "- clean-build" else "<δ/non-clean-build>"} @@ -128,7 +128,7 @@ object ServerMain { s"""ServerMain.java Loaded >>> |- version ${MornySystem.VERSION_FULL} |- Morny ${MornySystem.CODENAME toUpperCase} - |- <${MornySystem.getJarMd5}> [${BuildConfig.CODE_TIMESTAMP}]""".stripMargin + |- <${MornySystem.getJarMD5}> [${BuildConfig.CODE_TIMESTAMP}]""".stripMargin /// /// Check Coeur arguments @@ -143,7 +143,7 @@ object ServerMain { Thread.currentThread setName THREAD_MORNY_INIT try - MornyCoeur.init(new MornyConfig(config)) + MornyCoeur.init(using config build) catch { case _: CheckFailure.NullTelegramBotKey => logger.info("Parameter required has no value:\n --token.") 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 a2e38b7..7971d95 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 @@ -19,12 +19,12 @@ object DirectMsgClear extends ISimpleCommand { logger debug "executing command /r" if (event.message.replyToMessage == null) return; logger trace "message is a reply" - if (event.message.replyToMessage.from.id != MornyCoeur.getUserid) return; + if (event.message.replyToMessage.from.id != MornyCoeur.userid) return; logger trace "message replied is from me" if (System.currentTimeMillis/1000 - event.message.replyToMessage.date > 48*60*60) return; logger trace "message is not outdated(48 hrs ago)" - val isTrusted = MornyCoeur.trustedInstance isTrusted event.message.from.id + val isTrusted = MornyCoeur.trusted isTrusted event.message.from.id def _isReplyTrusted: Boolean = if (event.message.replyToMessage.replyToMessage == null) false else if (event.message.replyToMessage.replyToMessage.from.id == event.message.from.id) true 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 8bb3987..975c47b 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 @@ -57,7 +57,7 @@ object Encryptor extends ITelegramCommand { val _r = event.message.replyToMessage if ((_r ne null) && (_r.document ne null)) { try {XFile( - MornyCoeur.getAccount getFileContent (MornyCoeur.extra exec GetFile(_r.document.fileId)).file, + MornyCoeur.account getFileContent (MornyCoeur.extra exec GetFile(_r.document.fileId)).file, _r.document.fileName )} catch case e: IOException => logger warn s"NetworkRequest error: TelegramFileAPI:\n\t${e.getMessage}" @@ -74,7 +74,7 @@ object Encryptor extends ITelegramCommand { _photo_size = _size if (_photo_origin eq null) throw IllegalArgumentException("no photo from api.") XFile( - MornyCoeur.getAccount getFileContent (MornyCoeur.extra exec GetFile(_photo_origin.fileId)).file, + MornyCoeur.account getFileContent (MornyCoeur.extra exec GetFile(_photo_origin.fileId)).file, s"photo${byteArrayToHex(hashMd5(System.currentTimeMillis toString)) substring 32-12 toUpperCase}.png" ) } catch 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 6118412..5a6d9e8 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 @@ -40,7 +40,7 @@ object EventHack extends ITelegramCommand { ) x_mode match case "any" => - if (MornyCoeur.trustedInstance isTrusted event.message.from.id) + if (MornyCoeur.trusted isTrusted event.message.from.id) doRegister(HackType ANY) done_ok else done_forbiddenForAny 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 f4c414b..7799e06 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 @@ -39,7 +39,7 @@ object GetUsernameAndId extends ITelegramCommand { } else if (event.message.replyToMessage eq null) event.message.from.id else event.message.replyToMessage.from.id - val response = MornyCoeur.getAccount execute GetChatMember(event.message.chat.id, userId) + val response = MornyCoeur.account execute GetChatMember(event.message.chat.id, userId) if (response.chatMember eq null) MornyCoeur.extra exec SendMessage( 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 5d78ea1..b49f50d 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 @@ -65,12 +65,12 @@ object IP186Query { } catch case e: Exception => import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h - MornyCoeur.extra().exec(new SendMessage( + MornyCoeur.extra exec new SendMessage( event.message().chat().id(), s"""[Exception] in query: |${h(e.getMessage)}""" .stripMargin - ).parseMode(ParseMode.HTML).replyToMessageId(event.message().messageId())); + ).parseMode(ParseMode.HTML).replyToMessageId(event.message().messageId()) } 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 index 7fa9876..a6fbdf8 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyCommands.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyCommands.scala @@ -3,20 +3,23 @@ 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 cc.sukazyo.cono.morny.Log.logger 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)) + val stash = mutable.SeqMap.empty[String, ISimpleCommand] + for (i <- commands) + stash += (i.name -> i) + if (i.aliases ne null) for (alias <- i.aliases) + stash += (alias.name -> i) stash private val commands: CommandMap = CommandMap( @@ -41,12 +44,14 @@ object MornyCommands { Testing, DirectMsgClear, + //noinspection NonAsciiCharacters 私わね, + //noinspection NonAsciiCharacters 喵呜.Progynova ) - @SuppressWarnings(Array("NonAsciiCharacters")) + //noinspection NonAsciiCharacters val commands_uni: CommandMap = CommandMap( 喵呜.抱抱, 喵呜.揉揉, 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 9b3dae3..f9c46bb 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 @@ -1,10 +1,10 @@ package cc.sukazyo.cono.morny.bot.command +import cc.sukazyo.cono.morny.{BuildConfig, MornyAbout, MornyCoeur, MornySystem} import cc.sukazyo.cono.morny.data.{TelegramImages, TelegramStickers} import cc.sukazyo.cono.morny.util.CommonFormat.{formatDate, formatDuration} import cc.sukazyo.cono.morny.util.tgapi.InputCommand import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h -import cc.sukazyo.cono.morny.{BuildConfig, MornyAbout, MornyCoeur, MornySystem} import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.model.request.ParseMode import com.pengrad.telegrambot.request.{SendMessage, SendPhoto, SendSticker} @@ -38,7 +38,7 @@ object MornyInformation extends ITelegramCommand { val action: String = command.getArgs()(0) action match { - case Subs.STICKERS => echoStickers + case s if s startsWith Subs.STICKERS => echoStickers case Subs.RUNTIME => echoRuntime case Subs.VERSION | Subs.VERSION_2 => echoVersion case _ => echo404 @@ -93,24 +93,41 @@ object MornyInformation extends ITelegramCommand { } 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) == Subs.STICKERS) { - if (command.getArgs.length == 1) sid = "" - else if (command.getArgs.length == 2) sid = command.getArgs()(1) - } else if (command.getArgs.length == 1) { - if ((command.getArgs()(0) startsWith s"${Subs.STICKERS}.") || (command.getArgs()(0) startsWith s"${Subs.STICKERS}#")) { - sid = command.getArgs()(0) substring Subs.STICKERS.length+1 - } - } - if (sid == null) echo404 - else echoStickers(sid, chat, replyTo) + val mid: String|Null = + if (command.getArgs()(0) == Subs.STICKERS) { + if (command.getArgs.length == 1) "" + else if (command.getArgs.length == 2) command.getArgs()(1) + else null + } else if (command.getArgs.length == 1) { + if ((command.getArgs()(0) startsWith s"${Subs.STICKERS}.") || (command.getArgs()(0) startsWith s"${Subs.STICKERS}#")) { + command.getArgs()(0) substring Subs.STICKERS.length+1 + } else null + } else null + if (mid == null) echo404 + else echoStickers(mid)(using event.message.chat.id, event.message.messageId) } - private def echoStickers (sid: String, send_chat: Long, send_replyTo: Int): Unit = { - if (sid isEmpty) TelegramStickers echoAllStickers(MornyCoeur.extra, send_chat, send_replyTo) - else TelegramStickers echoStickerByID(sid, MornyCoeur.extra, send_chat, send_replyTo) + private def echoStickers (mid: String)(using send_chat: Long, send_replyTo: Int)(using Update): Unit = { + import scala.jdk.CollectionConverters.* + if (mid isEmpty) for ((_key, _file_id) <- TelegramStickers.map asScala) + echoSticker(_key, _file_id) + else { + try { + val sticker = TelegramStickers getById mid + echoSticker(sticker.getKey, sticker.getValue) + } catch case _: NoSuchFieldException => { + echo404 + } + } + } + + private def echoSticker (mid: String, file_id: String)(using send_chat: Long, send_replyTo: Int): Unit = { + val send_mid = SendMessage(send_chat, mid) + val send_sticker = SendSticker(send_chat, file_id) + if (send_replyTo != -1) send_mid.replyToMessageId(send_replyTo) + val result_send_mid = MornyCoeur.extra exec send_mid + send_sticker.replyToMessageId(result_send_mid.message.messageId) + MornyCoeur.extra exec send_sticker } private[command] def echoVersion (using event: Update): Unit = { @@ -123,7 +140,7 @@ object MornyInformation extends ITelegramCommand { |- Morny ${h(MornySystem.CODENAME toUpperCase)} |- ${h(MornySystem.VERSION_BASE)}$versionDeltaHTML${if (MornySystem.isGitBuild) "\n- " + versionGitHTML else ""} |coeur md5_hash: - |- ${h(MornySystem.getJarMd5)} + |- ${h(MornySystem.getJarMD5)} |coding timestamp: |- ${BuildConfig.CODE_TIMESTAMP} |- ${h(formatDate(BuildConfig.CODE_TIMESTAMP, 0))} [UTC] @@ -147,7 +164,7 @@ object MornyInformation extends ITelegramCommand { |- ${Runtime.getRuntime.availableProcessors} cores |coeur version: |- $getVersionAllFullTagHTML - |- ${h(MornySystem.getJarMd5)} + |- ${h(MornySystem.getJarMD5)} |- ${h(formatDate(BuildConfig.CODE_TIMESTAMP, 0))} [UTC] |- [${BuildConfig.CODE_TIMESTAMP}] |continuous: 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 index 7218dc9..bb69c48 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyManagers.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyManagers.scala @@ -24,7 +24,7 @@ object MornyManagers { val user = event.message.from - if (MornyCoeur.trustedInstance isTrusted user.id) { + if (MornyCoeur.trusted isTrusted user.id) { MornyCoeur.extra exec SendSticker( event.message.chat.id, @@ -59,7 +59,7 @@ object MornyManagers { val user = event.message.from - if (MornyCoeur.trustedInstance isTrusted user.id) { + if (MornyCoeur.trusted isTrusted user.id) { logger info s"call save from command by ${(TGToString as user) toStringLogTag}" MornyCoeur.callSaveData() 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 d8c334a..68ad75c 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 @@ -1,6 +1,5 @@ package cc.sukazyo.cono.morny.bot.event -import cc.sukazyo.cono.morny.Log.logger import cc.sukazyo.cono.morny.MornyCoeur import cc.sukazyo.cono.morny.bot.api.EventListener import cc.sukazyo.cono.morny.data.TelegramStickers @@ -20,6 +19,7 @@ object OnCallMe extends EventListener { if update.message.text == null then return false if update.message.chat.`type` != (Chat.Type Private) then return false + //noinspection ScalaUnnecessaryParentheses (update.message.text toLowerCase) match case "steam" | "sbeam" | "sdeam" => requestItem(update.message.from, "STEAM LIBRARY") @@ -51,7 +51,7 @@ object OnCallMe extends EventListener { private def requestLastDinner (req: Message): Unit = { var isAllowed = false var lastDinnerData: Message|Null = null - if (MornyCoeur.trustedInstance isTrustedForDinnerRead req.from.id) { + if (MornyCoeur.trusted isTrusted_dinnerReader req.from.id) { lastDinnerData = (MornyCoeur.extra exec GetChat(MornyCoeur.config.dinnerChatId)).chat.pinnedMessage val sendResp = MornyCoeur.extra exec ForwardMessage( req.from.id, 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 index a6fee41..d4bb8ca 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnCallMsgSend.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnCallMsgSend.scala @@ -46,6 +46,7 @@ object OnCallMsgSend extends EventListener { 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) + if e.customEmojiId ne null then _parsed.language(e.language) entities += _parsed MessageToSend(_body, entities toArray, parseMode, target) case _ => null @@ -59,7 +60,7 @@ object OnCallMsgSend extends EventListener { if message.text eq null then return false if !(message.text startsWith "*msg") then return false - if (!(MornyCoeur.trustedInstance isTrusted message.from.id)) + if (!(MornyCoeur.trusted isTrusted message.from.id)) MornyCoeur.extra exec SendSticker( message.chat.id, TelegramStickers ID_403 @@ -71,7 +72,7 @@ object OnCallMsgSend extends EventListener { 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() + val sendResponse = MornyCoeur.account execute messageToSend.toSendMessage() if (sendResponse isOk) { MornyCoeur.extra exec SendSticker( @@ -104,7 +105,7 @@ object OnCallMsgSend extends EventListener { if _toSend eq null then return answer404 else _toSend - val targetChatResponse = MornyCoeur.getAccount execute GetChat(messageToSend.targetId) + val targetChatResponse = MornyCoeur.account execute GetChat(messageToSend.targetId) if (targetChatResponse isOk) { def getChatDescriptionHTML (chat: Chat): String = import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h @@ -128,7 +129,7 @@ object OnCallMsgSend extends EventListener { } if messageToSend.message eq null then return true - val testSendResponse = MornyCoeur.getAccount execute messageToSend.toSendMessage(update.message.chat.id) + val testSendResponse = MornyCoeur.account execute messageToSend.toSendMessage(update.message.chat.id) .replyToMessageId(update.message.messageId) if (!(testSendResponse isOk)) MornyCoeur.extra exec SendMessage( 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 970aa2d..d4df473 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 @@ -2,7 +2,7 @@ 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.bot.query.InlineQueryUnit +import cc.sukazyo.cono.morny.bot.query.{InlineQueryUnit, MornyQueries} import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.model.request.InlineQueryResult import com.pengrad.telegrambot.request.AnswerInlineQuery @@ -15,7 +15,7 @@ object OnInlineQuery extends EventListener { override def onInlineQuery (using update: Update): Boolean = { - val results: List[InlineQueryUnit[_]] = MornyCoeur.queryManager query update + val results: List[InlineQueryUnit[_]] = MornyQueries query update var cacheTime = Int.MaxValue var isPersonal = InlineQueryUnit.defaults.IS_PERSONAL 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 index 5b2ab47..4e90c9b 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnMedicationNotifyApply.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnMedicationNotifyApply.scala @@ -2,7 +2,7 @@ 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 cc.sukazyo.cono.morny.daemon.{MedicationTimer, MornyDaemons} import com.pengrad.telegrambot.model.{Message, Update} object OnMedicationNotifyApply extends EventListener { @@ -14,7 +14,7 @@ object OnMedicationNotifyApply extends EventListener { private def editedMessageProcess (edited: Message): Boolean = { if edited.chat.id != MornyCoeur.config.medicationNotifyToChat then return false - MornyDaemons.medicationTimerInstance.refreshNotificationWrite(edited) + MedicationTimer.refreshNotificationWrite(edited) 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 index 526af48..b82a66a 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnTelegramCommand.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnTelegramCommand.scala @@ -22,7 +22,7 @@ object OnTelegramCommand extends EventListener { if (!(inputCommand.getCommand matches "^\\w+$")) logger debug "not command" false - else if ((inputCommand.getTarget ne null) && (inputCommand.getTarget ne MornyCoeur.getUsername)) + else if ((inputCommand.getTarget ne null) && (inputCommand.getTarget ne MornyCoeur.username)) logger debug "not morny command" false else 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 5f13657..0c06dc4 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 @@ -5,7 +5,7 @@ import com.pengrad.telegrambot.model.Update import scala.collection.mutable.ListBuffer -class MornyQueries { +object MornyQueries { private val queryInstances = Set[ITelegramQuery]( RawText, 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 14a4e81..6275c2e 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 @@ -14,7 +14,7 @@ object MyInformation extends ITelegramQuery { override def query (event: Update): List[InlineQueryUnit[_]] | Null = { - if (event.inlineQuery.query == null || (event.inlineQuery.query isBlank)) return null + if ((event.inlineQuery.query ne null) || (event.inlineQuery.query nonEmpty)) return null List( InlineQueryUnit(InlineQueryResultArticle( diff --git a/src/main/scala/cc/sukazyo/cono/morny/daemon/MedicationTimer.scala b/src/main/scala/cc/sukazyo/cono/morny/daemon/MedicationTimer.scala new file mode 100644 index 0000000..644abe2 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/daemon/MedicationTimer.scala @@ -0,0 +1,90 @@ +package cc.sukazyo.cono.morny.daemon + +import cc.sukazyo.cono.morny.MornyCoeur +import cc.sukazyo.cono.morny.Log.{exceptionLog, logger} +import com.pengrad.telegrambot.model.{Message, MessageEntity} +import com.pengrad.telegrambot.request.{EditMessageText, SendMessage} +import com.pengrad.telegrambot.response.SendResponse + +import java.time.{LocalDateTime, ZoneOffset} +import scala.collection.mutable.ArrayBuffer +import scala.language.implicitConversions + +object MedicationTimer extends Thread { + + private val NOTIFY_MESSAGE = "🍥⏲" + private val DAEMON_THREAD_NAME_DEF = "MedicationTimer" + + private val use_timeZone = MornyCoeur.config.medicationTimerUseTimezone + import scala.jdk.CollectionConverters.SetHasAsScala + private val notify_atHour: Set[Int] = MornyCoeur.config.medicationNotifyAt.asScala.toSet.map(_.intValue) + private val notify_toChat = MornyCoeur.config.medicationNotifyToChat + + this.setName(DAEMON_THREAD_NAME_DEF) + + private var lastNotify_messageId: Int|Null = _ + + override def run (): Unit = { + logger info "Medication Timer started." + while (!this.isInterrupted) { + try { + waitToNextRoutine() + sendNotification() + } catch + case _: InterruptedException => + interrupt() + logger info "MedicationTimer was interrupted, will be exit now" + case ill: IllegalArgumentException => + logger warn "MedicationTimer will not work due to: " + ill.getMessage + interrupt() + case e => + logger error + s"""unexpected error occurred on NotificationTimer + |${exceptionLog(e)}""" + .stripMargin + MornyReport.exception(e) + } + logger info "Medication Timer stopped." + } + + private def sendNotification(): Unit = { + val sendResponse: SendResponse = MornyCoeur.extra exec SendMessage(notify_toChat, NOTIFY_MESSAGE) + if sendResponse isOk then lastNotify_messageId = sendResponse.message.messageId + else lastNotify_messageId = null + } + + def refreshNotificationWrite (edited: Message): Unit = { + if lastNotify_messageId != (edited.messageId toInt) then return + import cc.sukazyo.cono.morny.util.CommonFormat.formatDate + val editTime = formatDate(edited.editDate*1000, use_timeZone.getTotalSeconds/60/60) + val entities = ArrayBuffer.empty[MessageEntity] + if edited.entities ne null then entities ++= edited.entities + entities += MessageEntity(MessageEntity.Type.italic, edited.text.length + "\n-- ".length, editTime.length) + MornyCoeur.extra exec EditMessageText( + notify_toChat, + edited.messageId, + edited.text + s"\n-- $editTime --" + ).entities(entities toArray:_*) + lastNotify_messageId = null + } + + @throws[IllegalArgumentException] + private[daemon] def calcNextRoutineTimestamp (baseTimeMillis: Long, zone: ZoneOffset, notifyAt: Set[Int]): Long = { + if (notifyAt isEmpty) throw new IllegalArgumentException("notify time is not set") + var time = LocalDateTime.ofEpochSecond( + baseTimeMillis/1000, ((baseTimeMillis%1000)*1000*1000) toInt, + zone + ).withMinute(0).withSecond(0).withNano(0) + time = time plusHours 1 + while (!(notifyAt contains (time getHour))) { + time = time plusHours 1 + } + (time toInstant zone) toEpochMilli + } + + @throws[InterruptedException | IllegalArgumentException] + private def waitToNextRoutine (): Unit = { + Thread sleep calcNextRoutineTimestamp(System.currentTimeMillis, use_timeZone, notify_atHour) + } + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/daemon/MornyDaemons.scala b/src/main/scala/cc/sukazyo/cono/morny/daemon/MornyDaemons.scala new file mode 100644 index 0000000..95c9415 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/daemon/MornyDaemons.scala @@ -0,0 +1,29 @@ +package cc.sukazyo.cono.morny.daemon + +import cc.sukazyo.cono.morny.Log.logger +import cc.sukazyo.cono.morny.MornyCoeur + +object MornyDaemons { + + def start (): Unit = { + logger info "ALL Morny Daemons starting..." + // TrackerDataManager.init(); + MedicationTimer.start() + MornyReport.onMornyLogin() + logger info "Morny Daemons started." + + } + + def stop (): Unit = { + logger.info("ALL Morny Daemons stopping...") + // TrackerDataManager.DAEMON.interrupt(); + MedicationTimer.interrupt() + // TrackerDataManager.trackingLock.lock(); + try { MedicationTimer.join() } + catch case e: InterruptedException => + e.printStackTrace(System.out) + MornyReport.onMornyExit(MornyCoeur.exitReason) + logger.info("ALL Morny Daemons STOPPED.") + } + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/daemon/MornyReport.scala b/src/main/scala/cc/sukazyo/cono/morny/daemon/MornyReport.scala new file mode 100644 index 0000000..cba4ccf --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/daemon/MornyReport.scala @@ -0,0 +1,122 @@ +package cc.sukazyo.cono.morny.daemon + +import cc.sukazyo.cono.morny.{MornyCoeur, MornyConfig} +import cc.sukazyo.cono.morny.util.tgapi.event.EventRuntimeException +import com.pengrad.telegrambot.request.{BaseRequest, SendMessage} +import com.pengrad.telegrambot.response.BaseResponse +import cc.sukazyo.cono.morny.Log.{exceptionLog, logger} +import cc.sukazyo.cono.morny.bot.command.MornyInformation +import com.google.gson.GsonBuilder +import com.pengrad.telegrambot.model.request.ParseMode +import com.pengrad.telegrambot.model.User +import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h +import cc.sukazyo.cono.morny.util.tgapi.formatting.TGToString + +object MornyReport { + + private def unsupported: Boolean = (!MornyCoeur.available) || (MornyCoeur.config.reportToChat == -1) + + private def executeReport[T <: BaseRequest[T, R], R<: BaseResponse] (report: T): Unit = { + if unsupported then return + try { + MornyCoeur.extra exec report + } catch case e: EventRuntimeException.ActionFailed => { + logger warn + s"""cannot execute report to telegram: + |${exceptionLog(e) indent 4} + | tg-api response: + |${(e.getResponse toString) indent 4}""" + .stripMargin + } + } + + def exception (e: Throwable, description: String|Null = null): Unit = { + if unsupported then return + def _tgErrFormat: String = e match + case api: EventRuntimeException.ActionFailed => + // language=html + "\n\ntg-api error:\n

%s
" + .formatted(GsonBuilder().setPrettyPrinting().create.toJson(api.getResponse)) + case _ => "" + executeReport(SendMessage( + MornyCoeur.config.reportToChat, + // language=html + s"""▌Coeur Unexpected Exception + |${if description ne null then h(description)+"\n" else ""} + |
${h(exceptionLog(e))}
$_tgErrFormat""" + .stripMargin + ).parseMode(ParseMode HTML)) + } + + def unauthenticatedAction (action: String, user: User): Unit = { + if unsupported then return + executeReport(SendMessage( + MornyCoeur.config.reportToChat, + // language=html + s"""▌User unauthenticated action + |action: ${h(action)} + |by user ${(TGToString as user) fullnameRefHtml}""" + .stripMargin + ).parseMode(ParseMode HTML)) + } + + def onMornyLogin(): Unit = { + executeReport(SendMessage( + MornyCoeur.config.reportToChat, + // language=html + s"""▌Morny Logged in + |-v ${MornyInformation.getVersionAllFullTagHTML} + |as user ${MornyCoeur.username} + | + |as config fields: + |${sectionConfigFields(MornyCoeur.config)}""" + .stripMargin + ).parseMode(ParseMode HTML)) + } + + def sectionConfigFields (config: MornyConfig): String = { + val echo = StringBuilder() + for (field <- config.getClass.getFields) { + // language=html + echo ++= s"- ${field.getName} " + try { + if (field.isAnnotationPresent(classOf[MornyConfig.Sensitive])) { + echo ++= /*language=html*/ ": sensitive_field" + } else { + val value = field.get(config) + // language=html + echo ++= "= " ++= (if value eq null then "null" else s"${h(value.toString)}") + } + + } catch + // noinspection ScalaUnnecessaryParentheses + case e: (IllegalAccessException|IllegalArgumentException|NullPointerException) => + // language=html + echo ++= s": ${h("")}" + logger error + s"""error while reading config field ${field.getName} + |${exceptionLog(e)}""".stripMargin + exception(e, s"error while reading config field ${field.getName}") + echo ++= "\n" + } + echo dropRight 1 toString + } + + def onMornyExit (causedBy: AnyRef|Null): Unit = { + if unsupported then return + val causedTag = causedBy match + case u: User => (TGToString as u) fullnameRefHtml + case n if n == null => "UNKNOWN reason" + case a: AnyRef => /*language=html*/ s"${h(a.toString)}" + executeReport(SendMessage( + MornyCoeur.config.reportToChat, + // language=html + s"""▌Morny Exited + |from user @${MornyCoeur.username} + | + |by: $causedTag""" + .stripMargin + ).parseMode(ParseMode HTML)) + } + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/data/TelegramImages.scala b/src/main/scala/cc/sukazyo/cono/morny/data/TelegramImages.scala new file mode 100644 index 0000000..667d5d3 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/data/TelegramImages.scala @@ -0,0 +1,38 @@ +package cc.sukazyo.cono.morny.data + +import cc.sukazyo.cono.morny.MornyAssets + +import scala.language.postfixOps +import scala.util.Using +import java.io.IOException +import cc.sukazyo.cono.morny.Log.{exceptionLog, logger} +import cc.sukazyo.cono.morny.daemon.MornyReport + +object TelegramImages { + + class AssetsFileImage (assetsPath: String) { + + private var cache: Array[Byte]|Null = _ + + def get:Array[Byte] = + if cache eq null then read() + if cache eq null then throw IllegalStateException("Failed to get assets file image.") + cache + + private def read (): Unit = { + Using ((MornyAssets.pack getResource assetsPath)read) { stream => + try { this.cache = stream.readAllBytes() } + catch case e: IOException => { + logger error + s"""Cannot read resource file: + |${exceptionLog(e)}""".stripMargin + MornyReport.exception(e, "Cannot read resource file.") + } + } + } + + } + + val IMG_ABOUT: AssetsFileImage = AssetsFileImage("images/featured-image@0.5x.jpg") + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/data/TelegramStickers.java b/src/main/scala/cc/sukazyo/cono/morny/data/TelegramStickers.java new file mode 100644 index 0000000..10a017a --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/data/TelegramStickers.java @@ -0,0 +1,53 @@ +package cc.sukazyo.cono.morny.data; + +import javax.annotation.Nonnull; +import java.lang.reflect.Field; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * 存放 bot 使用到的贴纸 + * @since 0.4.2.0 + */ +public class TelegramStickers { + + public static final String ID_ONLINE_STATUS_RETURN = "CAACAgEAAx0CW-CvvgAC5eBhhhODGRuu0pxKLwoQ3yMsowjviAACcycAAnj8xgVVU666si1utiIE"; + public static final String ID_HELLO = "CAACAgEAAxkBAAMnYYYWKNXO4ibo9dlsmDctHhhV6fIAAqooAAJ4_MYFJJhrHS74xUAiBA"; + public static final String ID_EXIT = "CAACAgEAAxkBAAMoYYYWt8UjvP0N405SAyvg2SQZmokAAkMiAAJ4_MYFw6yZLu06b-MiBA"; + public static final String ID_403 = "CAACAgEAAxkBAAMqYYYa_7hpXH6hMOYMX4Nh8AVYd74AAnQnAAJ4_MYFRdmmsQKLDZgiBA"; + public static final String ID_404 = "CAACAgEAAx0CSQh32gABA966YbRJpbmi2lCHINBDuo1DknSTsbsAAqUoAAJ4_MYFUa8SIaZriAojBA"; + public static final String ID_WAITING = "CAACAgEAAx0CSQh32gABA-8DYbh7W2VhJ490ucfZMUMrgMR2FW4AAm4nAAJ4_MYFjx6zpxJPWsQjBA"; + public static final String ID_SENT = "CAACAgEAAx0CSQh32gABA--zYbiyU_wOijEitp-0tSl_k7W6l3gAAgMmAAJ4_MYF4GrompjXPx4jBA"; + public static final String ID_SAVED = "CAACAgEAAx0CSQh32gABBExuYdB_G0srfhQldRWkBYxWzCOv4-IAApooAAJ4_MYFcjuNZszfQcQjBA"; + public static final String ID_PROGYNOVA = "CAACAgUAAxkBAAICm2KEuL7UQqNP7vSPCg2DHJIND6UsAAKLAwACH4WSBszIo722aQ3jJAQ"; + public static final String ID_NETWORK_ERR = "CAACAgEAAxkBAAID0WNJgNEkD726KW4vZeFlw0FlVVyNAAIXJgACePzGBb50o7O1RbxoKgQ"; + + @Nonnull + public static Map map () { + final LinkedHashMap mapping = new LinkedHashMap<>(); + for (Field object : TelegramStickers.class.getFields()) { + if (object.getType()==String.class && object.getName().startsWith("ID_")) { + try { + mapping.put(object.getName(), (String)object.get("")); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + } + return mapping; + } + + @Nonnull + public static Map.Entry getById (@Nonnull String stickerFieldID) + throws NoSuchFieldException { + try { + // normally get the sticker and echo + Field field = TelegramStickers.class.getField(stickerFieldID); + return Map.entry(field.getName(), (String)field.get("")); + } catch (IllegalAccessException e) { + // java-reflect get sticker FILE_ID failed + throw new RuntimeException(e); + } + } + +} diff --git a/src/main/old/cc/sukazyo/cono/morny/internal/BuildConfigField.java b/src/main/scala/cc/sukazyo/cono/morny/internal/BuildConfigField.java similarity index 100% rename from src/main/old/cc/sukazyo/cono/morny/internal/BuildConfigField.java rename to src/main/scala/cc/sukazyo/cono/morny/internal/BuildConfigField.java diff --git a/src/main/scala/cc/sukazyo/cono/morny/internal/ScalaJavaConv.scala b/src/main/scala/cc/sukazyo/cono/morny/internal/ScalaJavaConv.scala new file mode 100644 index 0000000..3547a2b --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/internal/ScalaJavaConv.scala @@ -0,0 +1,12 @@ +package cc.sukazyo.cono.morny.internal + +import scala.jdk.CollectionConverters._ +import scala.collection.immutable as simm +import java.util as j + +object ScalaJavaConv { + + def jSetInteger2simm (data: j.Set[Integer]): simm.Set[Int] = + data.asScala.toSet.map(_.intValue) + +} diff --git a/src/test/java/cc/sukazyo/cono/morny/MornyCLI.java b/src/test/java/cc/sukazyo/cono/morny/MornyCLI.java index e634582..4a36d44 100644 --- a/src/test/java/cc/sukazyo/cono/morny/MornyCLI.java +++ b/src/test/java/cc/sukazyo/cono/morny/MornyCLI.java @@ -8,7 +8,7 @@ public class MornyCLI { public static void main (String[] args) { - System.out.print("$ java -jar morny-coeur-"+MornySystem.VERSION_FULL+".jar " ); + System.out.print("$ java -jar morny-coeur-"+MornySystem.VERSION_FULL()+".jar " ); String x; try (Scanner line = new Scanner(System.in)) { x = line.nextLine(); } ServerMain.main(UniversalCommand.format(x)); diff --git a/src/test/java/cc/sukazyo/cono/morny/daemon/TestMedicationTimer.java b/src/test/java/cc/sukazyo/cono/morny/daemon/TestMedicationTimer.java index 58600ce..d686ea0 100644 --- a/src/test/java/cc/sukazyo/cono/morny/daemon/TestMedicationTimer.java +++ b/src/test/java/cc/sukazyo/cono/morny/daemon/TestMedicationTimer.java @@ -8,6 +8,8 @@ import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.util.Set; +import static cc.sukazyo.cono.morny.internal.ScalaJavaConv.jSetInteger2simm; + public class TestMedicationTimer { @ParameterizedTest @@ -21,12 +23,12 @@ public class TestMedicationTimer { 2125-11-18T23:45:27.062+00, +00, 2125-11-19T07:00:00+00 """) void testCalcNextRoutineTimestamp (ZonedDateTime base, ZoneOffset zoneHour, ZonedDateTime expected) - throws MedicationTimer.NoNotifyTimeTag { + throws IllegalArgumentException { final Set at = Set.of(7, 19, 21); System.out.println("base.toInstant().toEpochMilli() = " + base.toInstant().toEpochMilli()); Assertions.assertEquals( expected.toInstant().toEpochMilli(), - MedicationTimer.calcNextRoutineTimestamp(base.toInstant().toEpochMilli(), zoneHour, at) + MedicationTimer.calcNextRoutineTimestamp(base.toInstant().toEpochMilli(), zoneHour, jSetInteger2simm(at)) ); System.out.println(" ok"); } From a8b7562b51e0d5a857fcd96ffa6823b07ed66c36 Mon Sep 17 00:00:00 2001 From: Eyre_S Date: Sat, 16 Sep 2023 23:12:44 +0800 Subject: [PATCH 4/5] complete scala port --- .dockerignore | 2 - .editorconfig | 928 +++++++++++++++++- .gitignore | 2 - build.gradle | 23 +- gradle.properties | 5 +- .../cc/sukazyo/cono/morny/util/BiliTool.java | 98 -- .../cono/morny/util/CommonConvert.java | 61 -- .../cono/morny/util/CommonEncrypt.java | 144 --- .../sukazyo/cono/morny/util/CommonFormat.java | 30 - .../sukazyo/cono/morny/util/CommonRandom.java | 44 - .../cc/sukazyo/cono/morny/util/FileUtils.java | 28 - .../sukazyo/cono/morny/util/OkHttpPublic.java | 13 - .../cono/morny/util/UniversalCommand.java | 49 - .../cono/morny/util/tgapi/InputCommand.java | 66 -- .../cono/morny/util/tgapi/Standardize.java | 7 - .../tgapi/event/EventRuntimeException.java | 35 - .../util/tgapi/formatting/MsgEscape.java | 15 - .../util/tgapi/formatting/NamedUtils.java | 18 - .../util/tgapi/formatting/TGToString.java | 21 - .../tgapi/formatting/TGToStringFromChat.java | 60 -- .../formatting/TGToStringFromMessage.java | 27 - .../tgapi/formatting/TGToStringFromUser.java | 53 - .../formatting/TelegramUserInformation.java | 85 -- .../cc/sukazyo/cono/morny/MornyCoeur.scala | 2 +- .../cc/sukazyo/cono/morny/MornySystem.scala | 4 +- .../morny/bot/api/EventListenerManager.scala | 4 +- .../cono/morny/bot/command/Encryptor.scala | 91 +- .../cono/morny/bot/command/EventHack.scala | 6 +- .../morny/bot/command/GetUsernameAndId.scala | 4 +- .../cono/morny/bot/command/IP186Query.scala | 14 +- .../morny/bot/command/MornyCommands.scala | 8 +- .../cono/morny/bot/command/MornyHellos.scala | 2 +- .../morny/bot/command/MornyInformation.scala | 18 +- .../bot/command/MornyInformationOlds.scala | 1 + .../morny/bot/command/MornyManagers.scala | 16 +- .../cono/morny/bot/command/MornyOldJrrp.scala | 10 +- .../cono/morny/bot/command/Nbnhhsh.scala | 7 +- .../cono/morny/bot/command/私わね.scala | 5 +- .../cono/morny/bot/event/OnCallMe.scala | 8 +- .../cono/morny/bot/event/OnCallMsgSend.scala | 7 +- .../morny/bot/event/OnEventHackHandle.scala | 5 +- .../morny/bot/event/OnQuestionMarkReply.scala | 5 +- .../morny/bot/event/OnTelegramCommand.scala | 8 +- .../cono/morny/bot/event/OnUserRandom.scala | 6 +- .../morny/bot/event/OnUserSlashAction.scala | 12 +- .../cono/morny/bot/query/MyInformation.scala | 6 +- .../cono/morny/bot/query/RawText.scala | 4 +- .../morny/bot/query/ShareToolBilibili.scala | 6 +- .../morny/bot/query/ShareToolTwitter.scala | 7 +- .../cono/morny/daemon/MornyReport.scala | 18 +- .../sukazyo/cono/morny/data/MornyJrrp.scala | 6 +- .../cc/sukazyo/cono/morny/util/BiliTool.scala | 119 +++ .../cono/morny/util/CommonEncrypt.scala | 98 ++ .../cono/morny/util/CommonFormat.scala | 76 ++ .../cono/morny/util/ConvertByteHex.scala | 55 ++ .../sukazyo/cono/morny/util/FileUtils.scala | 28 + .../cono/morny/util/OkHttpPublic.scala | 13 + .../cono/morny/util/UniversalCommand.scala | 75 ++ .../cc/sukazyo/cono/morny/util/UseMath.scala | 19 + .../sukazyo/cono/morny/util/UseRandom.scala | 33 + .../cc/sukazyo/cono/morny/util/package.scala | 22 + .../cono/morny/util/tgapi/ExtraAction.java | 0 .../cono/morny/util/tgapi/InputCommand.scala | 31 + .../cono/morny/util/tgapi/Standardize.scala | 9 + .../tgapi/event/EventRuntimeException.scala | 9 + .../util/tgapi/formatting/NamingUtils.scala | 11 + .../tgapi/formatting/TelegramFormatter.scala | 82 ++ .../formatting/TelegramParseEscape.scala | 12 + .../formatting/TelegramUserInformation.scala | 67 ++ .../cono/morny/util/tgapi/package.scala | 4 + .../java/cc/sukazyo/cono/morny/MornyCLI.java | 18 - .../morny/daemon/TestMedicationTimer.java | 36 - .../sukazyo/cono/morny/util/TestBiliTool.java | 30 - .../cono/morny/util/TestCommonConvert.java | 47 - .../cono/morny/util/TestCommonEncrypt.java | 23 - .../cono/morny/util/TestCommonFormat.java | 36 - .../cc/sukazyo/cono/morny/MornyCLI.scala | 12 + .../sukazyo/cono/morny/test/MornyTests.scala | 10 + .../cono/morny/test/utils/BiliToolTest.scala | 68 ++ .../morny/test/utils/CommonEncryptTest.scala | 33 + .../morny/test/utils/CommonFormatTest.scala | 46 + .../morny/test/utils/ConvertByteHexTest.scala | 45 + .../cono/morny/test/utils/FileUtilsTest.scala | 9 + .../test/utils/UniversalCommandTest.scala | 75 ++ .../test/utils/tgapi/InputCommandTest.scala | 22 + .../tgapi/formatting/NamingUtilsTest.scala | 27 + .../formatting/TelegramFormatterTest.scala | 9 + .../formatting/TelegramParseEscapeTest.scala | 25 + .../TelegramUserInformationTest.scala | 26 + src/test/scala/live/LiveMain.scala | 9 + 90 files changed, 2287 insertions(+), 1186 deletions(-) delete mode 100644 src/main/java/cc/sukazyo/cono/morny/util/BiliTool.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/util/CommonConvert.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/util/CommonEncrypt.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/util/CommonFormat.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/util/CommonRandom.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/util/FileUtils.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/util/OkHttpPublic.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/util/UniversalCommand.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/util/tgapi/InputCommand.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/util/tgapi/Standardize.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/util/tgapi/event/EventRuntimeException.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/MsgEscape.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/NamedUtils.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToString.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromChat.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromMessage.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromUser.java delete mode 100644 src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramUserInformation.java create mode 100644 src/main/scala/cc/sukazyo/cono/morny/util/BiliTool.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/util/CommonEncrypt.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/util/CommonFormat.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/util/ConvertByteHex.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/util/FileUtils.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/util/OkHttpPublic.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/util/UniversalCommand.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/util/UseMath.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/util/UseRandom.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/util/package.scala rename src/main/{java => scala}/cc/sukazyo/cono/morny/util/tgapi/ExtraAction.java (100%) create mode 100644 src/main/scala/cc/sukazyo/cono/morny/util/tgapi/InputCommand.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/util/tgapi/Standardize.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/util/tgapi/event/EventRuntimeException.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/NamingUtils.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramFormatter.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramParseEscape.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramUserInformation.scala create mode 100644 src/main/scala/cc/sukazyo/cono/morny/util/tgapi/package.scala delete mode 100644 src/test/java/cc/sukazyo/cono/morny/MornyCLI.java delete mode 100644 src/test/java/cc/sukazyo/cono/morny/daemon/TestMedicationTimer.java delete mode 100644 src/test/java/cc/sukazyo/cono/morny/util/TestBiliTool.java delete mode 100644 src/test/java/cc/sukazyo/cono/morny/util/TestCommonConvert.java delete mode 100644 src/test/java/cc/sukazyo/cono/morny/util/TestCommonEncrypt.java delete mode 100644 src/test/java/cc/sukazyo/cono/morny/util/TestCommonFormat.java create mode 100644 src/test/scala/cc/sukazyo/cono/morny/MornyCLI.scala create mode 100644 src/test/scala/cc/sukazyo/cono/morny/test/MornyTests.scala create mode 100644 src/test/scala/cc/sukazyo/cono/morny/test/utils/BiliToolTest.scala create mode 100644 src/test/scala/cc/sukazyo/cono/morny/test/utils/CommonEncryptTest.scala create mode 100644 src/test/scala/cc/sukazyo/cono/morny/test/utils/CommonFormatTest.scala create mode 100644 src/test/scala/cc/sukazyo/cono/morny/test/utils/ConvertByteHexTest.scala create mode 100644 src/test/scala/cc/sukazyo/cono/morny/test/utils/FileUtilsTest.scala create mode 100644 src/test/scala/cc/sukazyo/cono/morny/test/utils/UniversalCommandTest.scala create mode 100644 src/test/scala/cc/sukazyo/cono/morny/test/utils/tgapi/InputCommandTest.scala create mode 100644 src/test/scala/cc/sukazyo/cono/morny/test/utils/tgapi/formatting/NamingUtilsTest.scala create mode 100644 src/test/scala/cc/sukazyo/cono/morny/test/utils/tgapi/formatting/TelegramFormatterTest.scala create mode 100644 src/test/scala/cc/sukazyo/cono/morny/test/utils/tgapi/formatting/TelegramParseEscapeTest.scala create mode 100644 src/test/scala/cc/sukazyo/cono/morny/test/utils/tgapi/formatting/TelegramUserInformationTest.scala create mode 100644 src/test/scala/live/LiveMain.scala diff --git a/.dockerignore b/.dockerignore index e23a3f5..f9ff432 100644 --- a/.dockerignore +++ b/.dockerignore @@ -4,8 +4,6 @@ .vscode/ .gradle/ .settings/ -/src/test/java/test/* -/src/test/resources/test/* #build /build/ diff --git a/.editorconfig b/.editorconfig index ee8e124..424d5bf 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,5 +1,3 @@ -root = true - [*] charset = utf-8 end_of_line = lf @@ -11,11 +9,50 @@ tab_width = 4 ij_continuation_indent_size = 8 ij_formatter_off_tag = @formatter:off ij_formatter_on_tag = @formatter:on -ij_formatter_tags_enabled = false +ij_formatter_tags_enabled = true ij_smart_tabs = false -ij_visual_guides = none +ij_visual_guides = ij_wrap_on_typing = false +[*.conf] +ij_smart_tabs = true +ij_hocon_keep_blank_lines_before_right_brace = 2 +ij_hocon_keep_indents_on_empty_lines = true +ij_hocon_keep_line_breaks = true +ij_hocon_space_after_colon = true +ij_hocon_space_after_comma = true +ij_hocon_space_before_colon = true +ij_hocon_space_before_comma = false +ij_hocon_spaces_within_braces = false +ij_hocon_spaces_within_brackets = false +ij_hocon_spaces_within_method_call_parentheses = false + +[*.css] +ij_smart_tabs = true +ij_css_align_closing_brace_with_properties = false +ij_css_blank_lines_around_nested_selector = 1 +ij_css_blank_lines_between_blocks = 1 +ij_css_block_comment_add_space = false +ij_css_brace_placement = end_of_line +ij_css_enforce_quotes_on_format = false +ij_css_hex_color_long_format = false +ij_css_hex_color_lower_case = true +ij_css_hex_color_short_format = false +ij_css_hex_color_upper_case = false +ij_css_keep_blank_lines_in_code = 2 +ij_css_keep_indents_on_empty_lines = true +ij_css_keep_single_line_blocks = false +ij_css_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow +ij_css_space_after_colon = true +ij_css_space_before_opening_brace = true +ij_css_use_double_quotes = true +ij_css_value_alignment = do_not_align + +[*.feature] +indent_size = 2 +indent_style = space +ij_gherkin_keep_indents_on_empty_lines = false + [*.java] ij_java_align_consecutive_assignments = false ij_java_align_consecutive_variable_declarations = false @@ -25,6 +62,7 @@ ij_java_align_multiline_array_initializer_expression = false ij_java_align_multiline_assignment = true ij_java_align_multiline_binary_operation = false ij_java_align_multiline_chained_methods = false +ij_java_align_multiline_deconstruction_list_components = true ij_java_align_multiline_extends_list = false ij_java_align_multiline_for = false ij_java_align_multiline_method_parentheses = false @@ -38,6 +76,7 @@ ij_java_align_multiline_text_blocks = false ij_java_align_multiline_throws_list = false ij_java_align_subsequent_simple_methods = false ij_java_align_throws_keyword = true +ij_java_align_types_in_multi_catch = true ij_java_annotation_parameter_wrap = off ij_java_array_initializer_new_line_after_left_brace = true ij_java_array_initializer_right_brace_on_new_line = true @@ -64,7 +103,7 @@ ij_java_blank_lines_before_package = 0 ij_java_block_brace_style = end_of_line ij_java_block_comment_add_space = false ij_java_block_comment_at_first_column = true -ij_java_builder_methods = none +ij_java_builder_methods = ij_java_call_parameters_new_line_after_left_paren = true ij_java_call_parameters_right_paren_on_new_line = true ij_java_call_parameters_wrap = normal @@ -74,8 +113,10 @@ ij_java_class_annotation_wrap = split_into_lines ij_java_class_brace_style = end_of_line ij_java_class_count_to_use_import_on_demand = 5 ij_java_class_names_in_javadoc = 1 +ij_java_deconstruction_list_wrap = normal ij_java_do_not_indent_top_level_class_members = false ij_java_do_not_wrap_after_single_annotation = false +ij_java_do_not_wrap_after_single_annotation_in_parameter = false ij_java_do_while_brace_force = never ij_java_doc_add_blank_line_after_description = true ij_java_doc_add_blank_line_after_param_comments = false @@ -96,18 +137,31 @@ ij_java_doc_param_description_on_new_line = false ij_java_doc_preserve_line_breaks = true ij_java_doc_use_throws_not_exception_tag = true ij_java_else_on_new_line = false +ij_java_entity_dd_prefix = ij_java_entity_dd_suffix = EJB +ij_java_entity_eb_prefix = ij_java_entity_eb_suffix = Bean +ij_java_entity_hi_prefix = ij_java_entity_hi_suffix = Home ij_java_entity_lhi_prefix = Local ij_java_entity_lhi_suffix = Home ij_java_entity_li_prefix = Local +ij_java_entity_li_suffix = ij_java_entity_pk_class = java.lang.String +ij_java_entity_ri_prefix = +ij_java_entity_ri_suffix = +ij_java_entity_vo_prefix = ij_java_entity_vo_suffix = VO ij_java_enum_constants_wrap = on_every_item ij_java_extends_keyword_wrap = normal ij_java_extends_list_wrap = off ij_java_field_annotation_wrap = normal +ij_java_field_name_prefix = +ij_java_field_name_suffix = +ij_java_filter_class_prefix = +ij_java_filter_class_suffix = +ij_java_filter_dd_prefix = +ij_java_filter_dd_suffix = ij_java_finally_on_new_line = false ij_java_for_brace_force = if_multiline ij_java_for_statement_new_line_after_left_paren = true @@ -139,8 +193,15 @@ ij_java_label_indent_size = 0 ij_java_lambda_brace_style = end_of_line ij_java_layout_static_imports_separately = true ij_java_line_comment_add_space = false +ij_java_line_comment_add_space_on_reformat = false ij_java_line_comment_at_first_column = true +ij_java_listener_class_prefix = +ij_java_listener_class_suffix = +ij_java_local_variable_name_prefix = +ij_java_local_variable_name_suffix = +ij_java_message_dd_prefix = ij_java_message_dd_suffix = EJB +ij_java_message_eb_prefix = ij_java_message_eb_suffix = Bean ij_java_method_annotation_wrap = split_into_lines ij_java_method_brace_style = end_of_line @@ -149,16 +210,22 @@ ij_java_method_parameters_new_line_after_left_paren = true ij_java_method_parameters_right_paren_on_new_line = true ij_java_method_parameters_wrap = normal ij_java_modifier_list_wrap = false +ij_java_multi_catch_types_wrap = normal ij_java_names_count_to_use_import_on_demand = 3 +ij_java_new_line_after_lparen_in_annotation = false +ij_java_new_line_after_lparen_in_deconstruction_pattern = true ij_java_new_line_after_lparen_in_record_header = false ij_java_packages_to_use_import_on_demand = java.awt.*,javax.swing.* ij_java_parameter_annotation_wrap = normal +ij_java_parameter_name_prefix = +ij_java_parameter_name_suffix = ij_java_parentheses_expression_new_line_after_left_paren = false ij_java_parentheses_expression_right_paren_on_new_line = false ij_java_place_assignment_sign_on_next_line = false ij_java_prefer_longer_names = true ij_java_prefer_parameters_wrap = false ij_java_record_components_wrap = normal +ij_java_repeat_annotations = ij_java_repeat_synchronized = true ij_java_replace_instanceof_and_cast = false ij_java_replace_null_check = true @@ -166,13 +233,26 @@ ij_java_replace_sum_lambda_with_method_ref = true ij_java_resource_list_new_line_after_left_paren = true ij_java_resource_list_right_paren_on_new_line = true ij_java_resource_list_wrap = normal +ij_java_rparen_on_new_line_in_annotation = false +ij_java_rparen_on_new_line_in_deconstruction_pattern = true ij_java_rparen_on_new_line_in_record_header = false +ij_java_servlet_class_prefix = +ij_java_servlet_class_suffix = +ij_java_servlet_dd_prefix = +ij_java_servlet_dd_suffix = +ij_java_session_dd_prefix = ij_java_session_dd_suffix = EJB +ij_java_session_eb_prefix = ij_java_session_eb_suffix = Bean +ij_java_session_hi_prefix = ij_java_session_hi_suffix = Home ij_java_session_lhi_prefix = Local ij_java_session_lhi_suffix = Home ij_java_session_li_prefix = Local +ij_java_session_li_suffix = +ij_java_session_ri_prefix = +ij_java_session_ri_suffix = +ij_java_session_si_prefix = ij_java_session_si_suffix = Service ij_java_space_after_closing_angle_bracket_in_type_argument = false ij_java_space_after_colon = true @@ -191,6 +271,7 @@ ij_java_space_before_class_left_brace = true ij_java_space_before_colon = true ij_java_space_before_colon_in_foreach = true ij_java_space_before_comma = false +ij_java_space_before_deconstruction_list = false ij_java_space_before_do_left_brace = true ij_java_space_before_else_keyword = true ij_java_space_before_else_left_brace = true @@ -221,6 +302,7 @@ ij_java_space_within_empty_array_initializer_braces = false ij_java_space_within_empty_method_call_parentheses = false ij_java_space_within_empty_method_parentheses = false ij_java_spaces_around_additive_operators = true +ij_java_spaces_around_annotation_eq = true ij_java_spaces_around_assignment_operators = true ij_java_spaces_around_bitwise_operators = true ij_java_spaces_around_equality_operators = true @@ -239,6 +321,7 @@ ij_java_spaces_within_braces = false ij_java_spaces_within_brackets = false ij_java_spaces_within_cast_parentheses = false ij_java_spaces_within_catch_parentheses = false +ij_java_spaces_within_deconstruction_list = false ij_java_spaces_within_for_parentheses = false ij_java_spaces_within_if_parentheses = false ij_java_spaces_within_method_call_parentheses = false @@ -250,9 +333,13 @@ ij_java_spaces_within_synchronized_parentheses = false ij_java_spaces_within_try_parentheses = false ij_java_spaces_within_while_parentheses = false ij_java_special_else_if_treatment = true +ij_java_static_field_name_prefix = +ij_java_static_field_name_suffix = +ij_java_subclass_name_prefix = ij_java_subclass_name_suffix = Impl ij_java_ternary_operation_signs_on_next_line = false ij_java_ternary_operation_wrap = on_every_item +ij_java_test_name_prefix = ij_java_test_name_suffix = Test ij_java_throws_keyword_wrap = normal ij_java_throws_list_wrap = off @@ -268,6 +355,303 @@ ij_java_wrap_comments = false ij_java_wrap_first_method_in_call_chain = true ij_java_wrap_long_lines = false +[*.less] +indent_size = 2 +indent_style = space +ij_less_align_closing_brace_with_properties = false +ij_less_blank_lines_around_nested_selector = 1 +ij_less_blank_lines_between_blocks = 1 +ij_less_block_comment_add_space = false +ij_less_brace_placement = 0 +ij_less_enforce_quotes_on_format = false +ij_less_hex_color_long_format = false +ij_less_hex_color_lower_case = false +ij_less_hex_color_short_format = false +ij_less_hex_color_upper_case = false +ij_less_keep_blank_lines_in_code = 2 +ij_less_keep_indents_on_empty_lines = false +ij_less_keep_single_line_blocks = false +ij_less_line_comment_add_space = false +ij_less_line_comment_at_first_column = false +ij_less_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow +ij_less_space_after_colon = true +ij_less_space_before_opening_brace = true +ij_less_use_double_quotes = true +ij_less_value_alignment = 0 + +[*.proto] +indent_size = 2 +indent_style = space +tab_width = 2 +ij_continuation_indent_size = 4 +ij_protobuf_keep_blank_lines_in_code = 2 +ij_protobuf_keep_indents_on_empty_lines = false +ij_protobuf_keep_line_breaks = true +ij_protobuf_space_after_comma = true +ij_protobuf_space_before_comma = false +ij_protobuf_spaces_around_assignment_operators = true +ij_protobuf_spaces_within_braces = false +ij_protobuf_spaces_within_brackets = false + +[*.sass] +indent_size = 2 +indent_style = space +ij_sass_align_closing_brace_with_properties = false +ij_sass_blank_lines_around_nested_selector = 1 +ij_sass_blank_lines_between_blocks = 1 +ij_sass_brace_placement = 0 +ij_sass_enforce_quotes_on_format = false +ij_sass_hex_color_long_format = false +ij_sass_hex_color_lower_case = false +ij_sass_hex_color_short_format = false +ij_sass_hex_color_upper_case = false +ij_sass_keep_blank_lines_in_code = 2 +ij_sass_keep_indents_on_empty_lines = false +ij_sass_keep_single_line_blocks = false +ij_sass_line_comment_add_space = false +ij_sass_line_comment_at_first_column = false +ij_sass_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow +ij_sass_space_after_colon = true +ij_sass_space_before_opening_brace = true +ij_sass_use_double_quotes = true +ij_sass_value_alignment = 0 + +[*.scala] +ij_continuation_indent_size = 4 +ij_smart_tabs = true +ij_scala_align_composite_pattern = true +ij_scala_align_extends_with = 0 +ij_scala_align_group_field_declarations = false +ij_scala_align_if_else = false +ij_scala_align_in_columns_case_branch = false +ij_scala_align_multiline_binary_operation = false +ij_scala_align_multiline_chained_methods = false +ij_scala_align_multiline_for = true +ij_scala_align_multiline_parameters = false +ij_scala_align_multiline_parameters_in_calls = false +ij_scala_align_multiline_parenthesized_expression = false +ij_scala_align_parameter_types_in_multiline_declarations = 0 +ij_scala_align_tuple_elements = false +ij_scala_alternate_continuation_indent_for_params = 4 +ij_scala_binary_operation_wrap = off +ij_scala_blank_lines_after_anonymous_class_header = 0 +ij_scala_blank_lines_after_class_header = 0 +ij_scala_blank_lines_after_imports = 1 +ij_scala_blank_lines_after_package = 1 +ij_scala_blank_lines_around_class = 1 +ij_scala_blank_lines_around_class_in_inner_scopes = 0 +ij_scala_blank_lines_around_field = 0 +ij_scala_blank_lines_around_field_in_inner_scopes = 0 +ij_scala_blank_lines_around_field_in_interface = 0 +ij_scala_blank_lines_around_method = 1 +ij_scala_blank_lines_around_method_in_inner_scopes = 1 +ij_scala_blank_lines_around_method_in_interface = 1 +ij_scala_blank_lines_before_class_end = 0 +ij_scala_blank_lines_before_imports = 1 +ij_scala_blank_lines_before_method_body = 0 +ij_scala_blank_lines_before_package = 0 +ij_scala_block_brace_style = end_of_line +ij_scala_block_comment_add_space = false +ij_scala_block_comment_at_first_column = true +ij_scala_call_parameters_new_line_after_lparen = 0 +ij_scala_call_parameters_right_paren_on_new_line = false +ij_scala_call_parameters_wrap = off +ij_scala_case_clause_brace_force = never +ij_scala_catch_on_new_line = false +ij_scala_class_annotation_wrap = split_into_lines +ij_scala_class_brace_style = end_of_line +ij_scala_closure_brace_force = never +ij_scala_do_not_align_block_expr_params = true +ij_scala_do_not_indent_case_clause_body = false +ij_scala_do_not_indent_tuples_close_brace = true +ij_scala_do_while_brace_force = never +ij_scala_else_on_new_line = false +ij_scala_enable_scaladoc_formatting = true +ij_scala_enforce_functional_syntax_for_unit = true +ij_scala_extends_keyword_wrap = off +ij_scala_extends_list_wrap = off +ij_scala_field_annotation_wrap = split_into_lines +ij_scala_finally_brace_force = never +ij_scala_finally_on_new_line = false +ij_scala_for_brace_force = never +ij_scala_for_statement_wrap = off +ij_scala_formatter = 0 +ij_scala_if_brace_force = never +ij_scala_implicit_value_class_prefix = +ij_scala_implicit_value_class_suffix = Ops +ij_scala_indent_braced_function_args = true +ij_scala_indent_case_from_switch = true +ij_scala_indent_fewer_braces_in_method_call_chains = false +ij_scala_indent_first_parameter = true +ij_scala_indent_first_parameter_clause = false +ij_scala_indent_type_arguments = true +ij_scala_indent_type_parameters = true +ij_scala_indent_yield_after_one_line_enumerators = true +ij_scala_keep_blank_lines_before_right_brace = 2 +ij_scala_keep_blank_lines_in_code = 2 +ij_scala_keep_blank_lines_in_declarations = 2 +ij_scala_keep_comments_on_same_line = true +ij_scala_keep_first_column_comment = false +ij_scala_keep_indents_on_empty_lines = true +ij_scala_keep_line_breaks = true +ij_scala_keep_one_line_lambdas_in_arg_list = false +ij_scala_keep_simple_blocks_in_one_line = false +ij_scala_keep_simple_methods_in_one_line = false +ij_scala_keep_xml_formatting = false +ij_scala_line_comment_add_space = false +ij_scala_line_comment_at_first_column = true +ij_scala_method_annotation_wrap = split_into_lines +ij_scala_method_brace_force = never +ij_scala_method_brace_style = end_of_line +ij_scala_method_call_chain_wrap = off +ij_scala_method_parameters_new_line_after_left_paren = true +ij_scala_method_parameters_right_paren_on_new_line = true +ij_scala_method_parameters_wrap = off +ij_scala_modifier_list_wrap = false +ij_scala_multiline_string_align_dangling_closing_quotes = false +ij_scala_multiline_string_closing_quotes_on_new_line = true +ij_scala_multiline_string_insert_margin_on_enter = true +ij_scala_multiline_string_margin_char = | +ij_scala_multiline_string_margin_indent = 2 +ij_scala_multiline_string_opening_quotes_on_new_line = true +ij_scala_multiline_string_process_margin_on_copy_paste = true +ij_scala_new_line_after_case_clause_arrow_when_multiline_body = false +ij_scala_newline_after_annotations = false +ij_scala_not_continuation_indent_for_params = false +ij_scala_parameter_annotation_wrap = off +ij_scala_parentheses_expression_new_line_after_left_paren = false +ij_scala_parentheses_expression_right_paren_on_new_line = false +ij_scala_place_closure_parameters_on_new_line = false +ij_scala_place_self_type_on_new_line = true +ij_scala_prefer_parameters_wrap = false +ij_scala_preserve_space_after_method_declaration_name = false +ij_scala_reformat_on_compile = false +ij_scala_replace_case_arrow_with_unicode_char = false +ij_scala_replace_for_generator_arrow_with_unicode_char = false +ij_scala_replace_lambda_with_greek_letter = false +ij_scala_replace_map_arrow_with_unicode_char = false +ij_scala_scalafmt_config_path = +ij_scala_scalafmt_fallback_to_default_settings = false +ij_scala_scalafmt_reformat_on_files_save = false +ij_scala_scalafmt_show_invalid_code_warnings = true +ij_scala_scalafmt_use_intellij_formatter_for_range_format = true +ij_scala_sd_align_exception_comments = true +ij_scala_sd_align_list_item_content = true +ij_scala_sd_align_other_tags_comments = true +ij_scala_sd_align_parameters_comments = true +ij_scala_sd_align_return_comments = true +ij_scala_sd_blank_line_after_parameters_comments = false +ij_scala_sd_blank_line_after_return_comments = false +ij_scala_sd_blank_line_before_parameters = false +ij_scala_sd_blank_line_before_tags = true +ij_scala_sd_blank_line_between_parameters = false +ij_scala_sd_keep_blank_lines_between_tags = true +ij_scala_sd_preserve_spaces_in_tags = false +ij_scala_space_after_comma = true +ij_scala_space_after_for_semicolon = true +ij_scala_space_after_modifiers_constructor = true +ij_scala_space_after_type_colon = true +ij_scala_space_before_brace_method_call = true +ij_scala_space_before_class_left_brace = true +ij_scala_space_before_for_parentheses = true +ij_scala_space_before_if_parentheses = true +ij_scala_space_before_infix_like_method_parentheses = false +ij_scala_space_before_infix_method_call_parentheses = false +ij_scala_space_before_infix_operator_like_method_call_parentheses = false +ij_scala_space_before_method_call_parentheses = false +ij_scala_space_before_method_left_brace = true +ij_scala_space_before_method_parentheses = true +ij_scala_space_before_type_colon = false +ij_scala_space_before_type_parameter_in_def_list = false +ij_scala_space_before_type_parameter_leading_context_bound_colon = false +ij_scala_space_before_type_parameter_leading_context_bound_colon_hk = true +ij_scala_space_before_type_parameter_list = false +ij_scala_space_before_type_parameter_rest_context_bound_colons = true +ij_scala_space_before_while_parentheses = true +ij_scala_space_inside_closure_braces = true +ij_scala_space_inside_self_type_braces = true +ij_scala_space_within_empty_method_call_parentheses = false +ij_scala_spaces_around_at_in_patterns = false +ij_scala_spaces_in_imports = false +ij_scala_spaces_in_one_line_blocks = false +ij_scala_spaces_within_brackets = false +ij_scala_spaces_within_for_parentheses = false +ij_scala_spaces_within_if_parentheses = false +ij_scala_spaces_within_method_call_parentheses = false +ij_scala_spaces_within_method_parentheses = false +ij_scala_spaces_within_parentheses = false +ij_scala_spaces_within_while_parentheses = false +ij_scala_special_else_if_treatment = true +ij_scala_trailing_comma_arg_list_enabled = true +ij_scala_trailing_comma_import_selector_enabled = false +ij_scala_trailing_comma_mode = trailing_comma_keep +ij_scala_trailing_comma_params_enabled = true +ij_scala_trailing_comma_pattern_arg_list_enabled = false +ij_scala_trailing_comma_tuple_enabled = false +ij_scala_trailing_comma_tuple_type_enabled = false +ij_scala_trailing_comma_type_params_enabled = false +ij_scala_try_brace_force = never +ij_scala_type_annotation_exclude_constant = true +ij_scala_type_annotation_exclude_in_dialect_sources = true +ij_scala_type_annotation_exclude_in_test_sources = false +ij_scala_type_annotation_exclude_member_of_anonymous_class = false +ij_scala_type_annotation_exclude_member_of_private_class = false +ij_scala_type_annotation_exclude_when_type_is_stable = true +ij_scala_type_annotation_function_parameter = false +ij_scala_type_annotation_implicit_modifier = true +ij_scala_type_annotation_local_definition = false +ij_scala_type_annotation_private_member = false +ij_scala_type_annotation_protected_member = true +ij_scala_type_annotation_public_member = true +ij_scala_type_annotation_structural_type = true +ij_scala_type_annotation_underscore_parameter = false +ij_scala_type_annotation_unit_type = true +ij_scala_use_alternate_continuation_indent_for_params = false +ij_scala_use_scala3_indentation_based_syntax = true +ij_scala_use_scaladoc2_formatting = true +ij_scala_variable_annotation_wrap = off +ij_scala_while_brace_force = never +ij_scala_while_on_new_line = false +ij_scala_wrap_before_with_keyword = false +ij_scala_wrap_first_method_in_call_chain = false +ij_scala_wrap_long_lines = false + +[*.scss] +indent_size = 2 +indent_style = space +ij_scss_align_closing_brace_with_properties = false +ij_scss_blank_lines_around_nested_selector = 1 +ij_scss_blank_lines_between_blocks = 1 +ij_scss_block_comment_add_space = false +ij_scss_brace_placement = 0 +ij_scss_enforce_quotes_on_format = false +ij_scss_hex_color_long_format = false +ij_scss_hex_color_lower_case = false +ij_scss_hex_color_short_format = false +ij_scss_hex_color_upper_case = false +ij_scss_keep_blank_lines_in_code = 2 +ij_scss_keep_indents_on_empty_lines = false +ij_scss_keep_single_line_blocks = false +ij_scss_line_comment_add_space = false +ij_scss_line_comment_at_first_column = false +ij_scss_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow +ij_scss_space_after_colon = true +ij_scss_space_before_opening_brace = true +ij_scss_use_double_quotes = true +ij_scss_value_alignment = 0 + +[*.vue] +indent_size = 2 +indent_style = space +tab_width = 2 +ij_continuation_indent_size = 4 +ij_vue_indent_children_of_top_level = template +ij_vue_interpolation_new_line_after_start_delimiter = true +ij_vue_interpolation_new_line_before_end_delimiter = true +ij_vue_interpolation_wrap = off +ij_vue_keep_indents_on_empty_lines = false +ij_vue_spaces_within_interpolation_expressions = true + [.editorconfig] ij_editorconfig_align_group_field_declarations = false ij_editorconfig_space_after_colon = false @@ -276,7 +660,7 @@ ij_editorconfig_space_before_colon = false ij_editorconfig_space_before_comma = false ij_editorconfig_spaces_around_assignment_operators = true -[{*.ant,*.fxml,*.isc,*.jhm,*.jnlp,*.jrxml,*.pom,*.rng,*.tld,*.wadl,*.wsdd,*.wsdl,*.xjb,*.xml,*.xsd,*.xsl,*.xslt,*.xul}] +[{*.ant,*.fxml,*.isc,*.jhm,*.jnlp,*.jrxml,*.pom,*.rng,*.tld,*.wadl,*.wsdl,*.xml,*.xsd,*.xsl,*.xslt,*.xul}] ij_smart_tabs = true ij_xml_align_attributes = false ij_xml_align_text = false @@ -297,7 +681,367 @@ ij_xml_space_inside_empty_tag = true ij_xml_text_wrap = normal ij_xml_use_custom_settings = false -[{*.gant,*.groovy,*.gson,*.gy}] +[{*.ats,*.cts,*.mts,*.ts}] +ij_continuation_indent_size = 4 +ij_smart_tabs = true +ij_typescript_align_imports = false +ij_typescript_align_multiline_array_initializer_expression = false +ij_typescript_align_multiline_binary_operation = false +ij_typescript_align_multiline_chained_methods = false +ij_typescript_align_multiline_extends_list = false +ij_typescript_align_multiline_for = false +ij_typescript_align_multiline_parameters = false +ij_typescript_align_multiline_parameters_in_calls = false +ij_typescript_align_multiline_ternary_operation = false +ij_typescript_align_object_properties = 0 +ij_typescript_align_union_types = false +ij_typescript_align_var_statements = 0 +ij_typescript_array_initializer_new_line_after_left_brace = false +ij_typescript_array_initializer_right_brace_on_new_line = false +ij_typescript_array_initializer_wrap = off +ij_typescript_assignment_wrap = off +ij_typescript_binary_operation_sign_on_next_line = false +ij_typescript_binary_operation_wrap = off +ij_typescript_blacklist_imports = rxjs/Rx,node_modules/**,**/node_modules/**,@angular/material,@angular/material/typings/** +ij_typescript_blank_lines_after_imports = 1 +ij_typescript_blank_lines_around_class = 1 +ij_typescript_blank_lines_around_field = 0 +ij_typescript_blank_lines_around_field_in_interface = 0 +ij_typescript_blank_lines_around_function = 1 +ij_typescript_blank_lines_around_method = 1 +ij_typescript_blank_lines_around_method_in_interface = 1 +ij_typescript_block_brace_style = end_of_line +ij_typescript_block_comment_add_space = false +ij_typescript_block_comment_at_first_column = true +ij_typescript_call_parameters_new_line_after_left_paren = true +ij_typescript_call_parameters_right_paren_on_new_line = true +ij_typescript_call_parameters_wrap = normal +ij_typescript_catch_on_new_line = false +ij_typescript_chained_call_dot_on_new_line = true +ij_typescript_class_brace_style = end_of_line +ij_typescript_comma_on_new_line = false +ij_typescript_do_while_brace_force = never +ij_typescript_else_on_new_line = false +ij_typescript_enforce_trailing_comma = keep +ij_typescript_enum_constants_wrap = on_every_item +ij_typescript_extends_keyword_wrap = off +ij_typescript_extends_list_wrap = off +ij_typescript_field_prefix = _ +ij_typescript_file_name_style = relaxed +ij_typescript_finally_on_new_line = false +ij_typescript_for_brace_force = never +ij_typescript_for_statement_new_line_after_left_paren = true +ij_typescript_for_statement_right_paren_on_new_line = true +ij_typescript_for_statement_wrap = on_every_item +ij_typescript_force_quote_style = false +ij_typescript_force_semicolon_style = false +ij_typescript_function_expression_brace_style = end_of_line +ij_typescript_if_brace_force = never +ij_typescript_import_merge_members = global +ij_typescript_import_prefer_absolute_path = global +ij_typescript_import_sort_members = true +ij_typescript_import_sort_module_name = false +ij_typescript_import_use_node_resolution = true +ij_typescript_imports_wrap = on_every_item +ij_typescript_indent_case_from_switch = true +ij_typescript_indent_chained_calls = false +ij_typescript_indent_package_children = 0 +ij_typescript_jsdoc_include_types = false +ij_typescript_jsx_attribute_value = braces +ij_typescript_keep_blank_lines_in_code = 2 +ij_typescript_keep_first_column_comment = false +ij_typescript_keep_indents_on_empty_lines = true +ij_typescript_keep_line_breaks = true +ij_typescript_keep_simple_blocks_in_one_line = false +ij_typescript_keep_simple_methods_in_one_line = false +ij_typescript_line_comment_add_space = true +ij_typescript_line_comment_at_first_column = false +ij_typescript_method_brace_style = end_of_line +ij_typescript_method_call_chain_wrap = off +ij_typescript_method_parameters_new_line_after_left_paren = true +ij_typescript_method_parameters_right_paren_on_new_line = true +ij_typescript_method_parameters_wrap = on_every_item +ij_typescript_object_literal_wrap = on_every_item +ij_typescript_object_types_wrap = on_every_item +ij_typescript_parentheses_expression_new_line_after_left_paren = true +ij_typescript_parentheses_expression_right_paren_on_new_line = true +ij_typescript_place_assignment_sign_on_next_line = false +ij_typescript_prefer_as_type_cast = false +ij_typescript_prefer_explicit_types_function_expression_returns = false +ij_typescript_prefer_explicit_types_function_returns = false +ij_typescript_prefer_explicit_types_vars_fields = false +ij_typescript_prefer_parameters_wrap = false +ij_typescript_property_prefix = +ij_typescript_reformat_c_style_comments = false +ij_typescript_space_after_colon = true +ij_typescript_space_after_comma = true +ij_typescript_space_after_dots_in_rest_parameter = false +ij_typescript_space_after_generator_mult = true +ij_typescript_space_after_property_colon = true +ij_typescript_space_after_quest = true +ij_typescript_space_after_type_colon = true +ij_typescript_space_after_unary_not = false +ij_typescript_space_before_async_arrow_lparen = true +ij_typescript_space_before_catch_keyword = true +ij_typescript_space_before_catch_left_brace = true +ij_typescript_space_before_catch_parentheses = true +ij_typescript_space_before_class_lbrace = true +ij_typescript_space_before_class_left_brace = true +ij_typescript_space_before_colon = true +ij_typescript_space_before_comma = false +ij_typescript_space_before_do_left_brace = true +ij_typescript_space_before_else_keyword = true +ij_typescript_space_before_else_left_brace = true +ij_typescript_space_before_finally_keyword = true +ij_typescript_space_before_finally_left_brace = true +ij_typescript_space_before_for_left_brace = true +ij_typescript_space_before_for_parentheses = true +ij_typescript_space_before_for_semicolon = false +ij_typescript_space_before_function_left_parenth = true +ij_typescript_space_before_generator_mult = false +ij_typescript_space_before_if_left_brace = true +ij_typescript_space_before_if_parentheses = true +ij_typescript_space_before_method_call_parentheses = false +ij_typescript_space_before_method_left_brace = true +ij_typescript_space_before_method_parentheses = true +ij_typescript_space_before_property_colon = false +ij_typescript_space_before_quest = true +ij_typescript_space_before_switch_left_brace = true +ij_typescript_space_before_switch_parentheses = true +ij_typescript_space_before_try_left_brace = true +ij_typescript_space_before_type_colon = false +ij_typescript_space_before_unary_not = false +ij_typescript_space_before_while_keyword = true +ij_typescript_space_before_while_left_brace = true +ij_typescript_space_before_while_parentheses = true +ij_typescript_spaces_around_additive_operators = true +ij_typescript_spaces_around_arrow_function_operator = true +ij_typescript_spaces_around_assignment_operators = true +ij_typescript_spaces_around_bitwise_operators = true +ij_typescript_spaces_around_equality_operators = true +ij_typescript_spaces_around_logical_operators = true +ij_typescript_spaces_around_multiplicative_operators = true +ij_typescript_spaces_around_relational_operators = true +ij_typescript_spaces_around_shift_operators = true +ij_typescript_spaces_around_unary_operator = false +ij_typescript_spaces_within_array_initializer_brackets = false +ij_typescript_spaces_within_brackets = false +ij_typescript_spaces_within_catch_parentheses = false +ij_typescript_spaces_within_for_parentheses = false +ij_typescript_spaces_within_if_parentheses = false +ij_typescript_spaces_within_imports = false +ij_typescript_spaces_within_interpolation_expressions = false +ij_typescript_spaces_within_method_call_parentheses = false +ij_typescript_spaces_within_method_parentheses = false +ij_typescript_spaces_within_object_literal_braces = false +ij_typescript_spaces_within_object_type_braces = false +ij_typescript_spaces_within_parentheses = false +ij_typescript_spaces_within_switch_parentheses = false +ij_typescript_spaces_within_type_assertion = false +ij_typescript_spaces_within_union_types = true +ij_typescript_spaces_within_while_parentheses = false +ij_typescript_special_else_if_treatment = true +ij_typescript_ternary_operation_signs_on_next_line = false +ij_typescript_ternary_operation_wrap = off +ij_typescript_union_types_wrap = on_every_item +ij_typescript_use_chained_calls_group_indents = false +ij_typescript_use_double_quotes = true +ij_typescript_use_explicit_js_extension = auto +ij_typescript_use_path_mapping = always +ij_typescript_use_public_modifier = false +ij_typescript_use_semicolon_after_statement = true +ij_typescript_var_declaration_wrap = normal +ij_typescript_while_brace_force = never +ij_typescript_while_on_new_line = false +ij_typescript_wrap_comments = false + +[{*.bash,*.sh,*.zsh}] +indent_size = 2 +tab_width = 2 +ij_shell_binary_ops_start_line = false +ij_shell_keep_column_alignment_padding = false +ij_shell_minify_program = false +ij_shell_redirect_followed_by_space = false +ij_shell_switch_cases_indented = true +ij_shell_use_unix_line_separator = true + +[{*.cjs,*.js}] +ij_continuation_indent_size = 4 +ij_javascript_align_imports = false +ij_javascript_align_multiline_array_initializer_expression = false +ij_javascript_align_multiline_binary_operation = false +ij_javascript_align_multiline_chained_methods = false +ij_javascript_align_multiline_extends_list = false +ij_javascript_align_multiline_for = true +ij_javascript_align_multiline_parameters = true +ij_javascript_align_multiline_parameters_in_calls = false +ij_javascript_align_multiline_ternary_operation = false +ij_javascript_align_object_properties = 0 +ij_javascript_align_union_types = false +ij_javascript_align_var_statements = 0 +ij_javascript_array_initializer_new_line_after_left_brace = true +ij_javascript_array_initializer_right_brace_on_new_line = true +ij_javascript_array_initializer_wrap = on_every_item +ij_javascript_assignment_wrap = off +ij_javascript_binary_operation_sign_on_next_line = false +ij_javascript_binary_operation_wrap = off +ij_javascript_blacklist_imports = rxjs/Rx,node_modules/**,**/node_modules/**,@angular/material,@angular/material/typings/** +ij_javascript_blank_lines_after_imports = 1 +ij_javascript_blank_lines_around_class = 1 +ij_javascript_blank_lines_around_field = 0 +ij_javascript_blank_lines_around_function = 1 +ij_javascript_blank_lines_around_method = 1 +ij_javascript_block_brace_style = end_of_line +ij_javascript_block_comment_add_space = false +ij_javascript_block_comment_at_first_column = true +ij_javascript_call_parameters_new_line_after_left_paren = true +ij_javascript_call_parameters_right_paren_on_new_line = true +ij_javascript_call_parameters_wrap = on_every_item +ij_javascript_catch_on_new_line = false +ij_javascript_chained_call_dot_on_new_line = false +ij_javascript_class_brace_style = end_of_line +ij_javascript_comma_on_new_line = false +ij_javascript_do_while_brace_force = never +ij_javascript_else_on_new_line = false +ij_javascript_enforce_trailing_comma = remove +ij_javascript_extends_keyword_wrap = off +ij_javascript_extends_list_wrap = off +ij_javascript_field_prefix = _ +ij_javascript_file_name_style = relaxed +ij_javascript_finally_on_new_line = false +ij_javascript_for_brace_force = if_multiline +ij_javascript_for_statement_new_line_after_left_paren = true +ij_javascript_for_statement_right_paren_on_new_line = true +ij_javascript_for_statement_wrap = on_every_item +ij_javascript_force_quote_style = false +ij_javascript_force_semicolon_style = false +ij_javascript_function_expression_brace_style = end_of_line +ij_javascript_if_brace_force = never +ij_javascript_import_merge_members = global +ij_javascript_import_prefer_absolute_path = global +ij_javascript_import_sort_members = true +ij_javascript_import_sort_module_name = false +ij_javascript_import_use_node_resolution = true +ij_javascript_imports_wrap = on_every_item +ij_javascript_indent_case_from_switch = true +ij_javascript_indent_chained_calls = false +ij_javascript_indent_package_children = 0 +ij_javascript_jsx_attribute_value = braces +ij_javascript_keep_blank_lines_in_code = 2 +ij_javascript_keep_first_column_comment = true +ij_javascript_keep_indents_on_empty_lines = true +ij_javascript_keep_line_breaks = true +ij_javascript_keep_simple_blocks_in_one_line = false +ij_javascript_keep_simple_methods_in_one_line = false +ij_javascript_line_comment_add_space = true +ij_javascript_line_comment_at_first_column = false +ij_javascript_method_brace_style = end_of_line +ij_javascript_method_call_chain_wrap = off +ij_javascript_method_parameters_new_line_after_left_paren = true +ij_javascript_method_parameters_right_paren_on_new_line = true +ij_javascript_method_parameters_wrap = on_every_item +ij_javascript_object_literal_wrap = on_every_item +ij_javascript_object_types_wrap = on_every_item +ij_javascript_parentheses_expression_new_line_after_left_paren = false +ij_javascript_parentheses_expression_right_paren_on_new_line = false +ij_javascript_place_assignment_sign_on_next_line = false +ij_javascript_prefer_as_type_cast = false +ij_javascript_prefer_explicit_types_function_expression_returns = false +ij_javascript_prefer_explicit_types_function_returns = false +ij_javascript_prefer_explicit_types_vars_fields = false +ij_javascript_prefer_parameters_wrap = false +ij_javascript_property_prefix = +ij_javascript_reformat_c_style_comments = true +ij_javascript_space_after_colon = true +ij_javascript_space_after_comma = true +ij_javascript_space_after_dots_in_rest_parameter = false +ij_javascript_space_after_generator_mult = true +ij_javascript_space_after_property_colon = true +ij_javascript_space_after_quest = true +ij_javascript_space_after_type_colon = true +ij_javascript_space_after_unary_not = false +ij_javascript_space_before_async_arrow_lparen = true +ij_javascript_space_before_catch_keyword = true +ij_javascript_space_before_catch_left_brace = true +ij_javascript_space_before_catch_parentheses = true +ij_javascript_space_before_class_lbrace = true +ij_javascript_space_before_class_left_brace = true +ij_javascript_space_before_colon = true +ij_javascript_space_before_comma = false +ij_javascript_space_before_do_left_brace = true +ij_javascript_space_before_else_keyword = true +ij_javascript_space_before_else_left_brace = true +ij_javascript_space_before_finally_keyword = true +ij_javascript_space_before_finally_left_brace = true +ij_javascript_space_before_for_left_brace = true +ij_javascript_space_before_for_parentheses = true +ij_javascript_space_before_for_semicolon = false +ij_javascript_space_before_function_left_parenth = true +ij_javascript_space_before_generator_mult = true +ij_javascript_space_before_if_left_brace = true +ij_javascript_space_before_if_parentheses = true +ij_javascript_space_before_method_call_parentheses = false +ij_javascript_space_before_method_left_brace = true +ij_javascript_space_before_method_parentheses = true +ij_javascript_space_before_property_colon = false +ij_javascript_space_before_quest = true +ij_javascript_space_before_switch_left_brace = true +ij_javascript_space_before_switch_parentheses = true +ij_javascript_space_before_try_left_brace = true +ij_javascript_space_before_type_colon = false +ij_javascript_space_before_unary_not = false +ij_javascript_space_before_while_keyword = true +ij_javascript_space_before_while_left_brace = true +ij_javascript_space_before_while_parentheses = true +ij_javascript_spaces_around_additive_operators = true +ij_javascript_spaces_around_arrow_function_operator = true +ij_javascript_spaces_around_assignment_operators = true +ij_javascript_spaces_around_bitwise_operators = true +ij_javascript_spaces_around_equality_operators = true +ij_javascript_spaces_around_logical_operators = true +ij_javascript_spaces_around_multiplicative_operators = true +ij_javascript_spaces_around_relational_operators = true +ij_javascript_spaces_around_shift_operators = true +ij_javascript_spaces_around_unary_operator = false +ij_javascript_spaces_within_array_initializer_brackets = false +ij_javascript_spaces_within_brackets = false +ij_javascript_spaces_within_catch_parentheses = false +ij_javascript_spaces_within_for_parentheses = false +ij_javascript_spaces_within_if_parentheses = false +ij_javascript_spaces_within_imports = false +ij_javascript_spaces_within_interpolation_expressions = false +ij_javascript_spaces_within_method_call_parentheses = false +ij_javascript_spaces_within_method_parentheses = false +ij_javascript_spaces_within_object_literal_braces = false +ij_javascript_spaces_within_object_type_braces = true +ij_javascript_spaces_within_parentheses = false +ij_javascript_spaces_within_switch_parentheses = false +ij_javascript_spaces_within_type_assertion = false +ij_javascript_spaces_within_union_types = true +ij_javascript_spaces_within_while_parentheses = false +ij_javascript_special_else_if_treatment = true +ij_javascript_ternary_operation_signs_on_next_line = false +ij_javascript_ternary_operation_wrap = on_every_item +ij_javascript_union_types_wrap = on_every_item +ij_javascript_use_chained_calls_group_indents = false +ij_javascript_use_double_quotes = false +ij_javascript_use_explicit_js_extension = auto +ij_javascript_use_path_mapping = always +ij_javascript_use_public_modifier = false +ij_javascript_use_semicolon_after_statement = false +ij_javascript_var_declaration_wrap = normal +ij_javascript_while_brace_force = never +ij_javascript_while_on_new_line = false +ij_javascript_wrap_comments = false + +[{*.comp,*.frag,*.fsh,*.geom,*.glsl,*.tesc,*.tese,*.vert,*.vsh}] +ij_glsl_keep_indents_on_empty_lines = true + +[{*.ft,*.vm,*.vsl}] +ij_smart_tabs = true +ij_vtl_keep_indents_on_empty_lines = true + +[{*.gant,*.groovy,*.gy}] ij_smart_tabs = true ij_groovy_align_group_field_declarations = false ij_groovy_align_multiline_array_initializer_expression = false @@ -344,6 +1088,7 @@ ij_groovy_class_brace_style = end_of_line ij_groovy_class_count_to_use_import_on_demand = 5 ij_groovy_do_while_brace_force = never ij_groovy_else_on_new_line = true +ij_groovy_enable_groovydoc_formatting = true ij_groovy_enum_constants_wrap = on_every_item ij_groovy_extends_keyword_wrap = normal ij_groovy_extends_list_wrap = off @@ -353,6 +1098,12 @@ ij_groovy_for_brace_force = never ij_groovy_for_statement_new_line_after_left_paren = true ij_groovy_for_statement_right_paren_on_new_line = true ij_groovy_for_statement_wrap = on_every_item +ij_groovy_ginq_general_clause_wrap_policy = 2 +ij_groovy_ginq_having_wrap_policy = 1 +ij_groovy_ginq_indent_having_clause = true +ij_groovy_ginq_indent_on_clause = true +ij_groovy_ginq_on_wrap_policy = 1 +ij_groovy_ginq_space_after_keyword = true ij_groovy_if_brace_force = never ij_groovy_import_annotation_wrap = 2 ij_groovy_imports_layout = *,|,javax.**,java.**,|,$* @@ -376,6 +1127,7 @@ ij_groovy_label_indent_size = 0 ij_groovy_lambda_brace_style = end_of_line ij_groovy_layout_static_imports_separately = true ij_groovy_line_comment_add_space = false +ij_groovy_line_comment_add_space_on_reformat = false ij_groovy_line_comment_at_first_column = true ij_groovy_method_annotation_wrap = split_into_lines ij_groovy_method_brace_style = end_of_line @@ -481,6 +1233,109 @@ ij_groovy_while_on_new_line = false ij_groovy_wrap_chain_calls_after_dot = false ij_groovy_wrap_long_lines = false +[{*.gradle.kts,*.kt,*.kts,*.main.kts,*.space.kts}] +ij_smart_tabs = true +ij_kotlin_align_in_columns_case_branch = false +ij_kotlin_align_multiline_binary_operation = false +ij_kotlin_align_multiline_extends_list = false +ij_kotlin_align_multiline_method_parentheses = false +ij_kotlin_align_multiline_parameters = true +ij_kotlin_align_multiline_parameters_in_calls = true +ij_kotlin_allow_trailing_comma = false +ij_kotlin_allow_trailing_comma_on_call_site = false +ij_kotlin_assignment_wrap = normal +ij_kotlin_blank_lines_after_class_header = 1 +ij_kotlin_blank_lines_around_block_when_branches = 0 +ij_kotlin_blank_lines_before_declaration_with_comment_or_annotation_on_separate_line = 1 +ij_kotlin_block_comment_add_space = false +ij_kotlin_block_comment_at_first_column = true +ij_kotlin_call_parameters_new_line_after_left_paren = true +ij_kotlin_call_parameters_right_paren_on_new_line = true +ij_kotlin_call_parameters_wrap = on_every_item +ij_kotlin_catch_on_new_line = false +ij_kotlin_class_annotation_wrap = split_into_lines +ij_kotlin_code_style_defaults = KOTLIN_OFFICIAL +ij_kotlin_continuation_indent_for_chained_calls = false +ij_kotlin_continuation_indent_for_expression_bodies = false +ij_kotlin_continuation_indent_in_argument_lists = false +ij_kotlin_continuation_indent_in_elvis = false +ij_kotlin_continuation_indent_in_if_conditions = false +ij_kotlin_continuation_indent_in_parameter_lists = false +ij_kotlin_continuation_indent_in_supertype_lists = false +ij_kotlin_else_on_new_line = false +ij_kotlin_enum_constants_wrap = on_every_item +ij_kotlin_extends_list_wrap = on_every_item +ij_kotlin_field_annotation_wrap = split_into_lines +ij_kotlin_finally_on_new_line = false +ij_kotlin_if_rparen_on_new_line = true +ij_kotlin_import_nested_classes = false +ij_kotlin_imports_layout = *,java.**,javax.**,kotlin.**,^ +ij_kotlin_insert_whitespaces_in_simple_one_line_method = true +ij_kotlin_keep_blank_lines_before_right_brace = 2 +ij_kotlin_keep_blank_lines_in_code = 2 +ij_kotlin_keep_blank_lines_in_declarations = 2 +ij_kotlin_keep_first_column_comment = false +ij_kotlin_keep_indents_on_empty_lines = true +ij_kotlin_keep_line_breaks = true +ij_kotlin_lbrace_on_next_line = false +ij_kotlin_line_break_after_multiline_when_entry = true +ij_kotlin_line_comment_add_space = false +ij_kotlin_line_comment_add_space_on_reformat = false +ij_kotlin_line_comment_at_first_column = true +ij_kotlin_method_annotation_wrap = split_into_lines +ij_kotlin_method_call_chain_wrap = on_every_item +ij_kotlin_method_parameters_new_line_after_left_paren = true +ij_kotlin_method_parameters_right_paren_on_new_line = true +ij_kotlin_method_parameters_wrap = on_every_item +ij_kotlin_name_count_to_use_star_import = 5 +ij_kotlin_name_count_to_use_star_import_for_members = 3 +ij_kotlin_packages_to_use_import_on_demand = java.util.*,kotlinx.android.synthetic.**,io.ktor.** +ij_kotlin_parameter_annotation_wrap = off +ij_kotlin_space_after_comma = true +ij_kotlin_space_after_extend_colon = true +ij_kotlin_space_after_type_colon = true +ij_kotlin_space_before_catch_parentheses = true +ij_kotlin_space_before_comma = false +ij_kotlin_space_before_extend_colon = true +ij_kotlin_space_before_for_parentheses = true +ij_kotlin_space_before_if_parentheses = true +ij_kotlin_space_before_lambda_arrow = true +ij_kotlin_space_before_type_colon = false +ij_kotlin_space_before_when_parentheses = true +ij_kotlin_space_before_while_parentheses = true +ij_kotlin_spaces_around_additive_operators = true +ij_kotlin_spaces_around_assignment_operators = true +ij_kotlin_spaces_around_equality_operators = true +ij_kotlin_spaces_around_function_type_arrow = true +ij_kotlin_spaces_around_logical_operators = true +ij_kotlin_spaces_around_multiplicative_operators = true +ij_kotlin_spaces_around_range = false +ij_kotlin_spaces_around_relational_operators = true +ij_kotlin_spaces_around_unary_operator = false +ij_kotlin_spaces_around_when_arrow = true +ij_kotlin_variable_annotation_wrap = off +ij_kotlin_while_on_new_line = false +ij_kotlin_wrap_elvis_expressions = 1 +ij_kotlin_wrap_expression_body_functions = 1 +ij_kotlin_wrap_first_method_in_call_chain = false + +[{*.har,*.jsb2,*.jsb3,*.json,.babelrc,.conf,.eslintrc,.prettierrc,.stylelintrc,bowerrc,jest.config,mcmod.info,meatball_from_mutton.json,pack.mcmeta}] +ij_smart_tabs = true +ij_json_array_wrapping = split_into_lines +ij_json_keep_blank_lines_in_code = 0 +ij_json_keep_indents_on_empty_lines = true +ij_json_keep_line_breaks = true +ij_json_keep_trailing_comma = false +ij_json_object_wrapping = split_into_lines +ij_json_property_alignment = do_not_align +ij_json_space_after_colon = true +ij_json_space_after_comma = true +ij_json_space_before_colon = false +ij_json_space_before_comma = false +ij_json_spaces_within_braces = false +ij_json_spaces_within_brackets = false +ij_json_wrap_long_lines = false + [{*.htm,*.html,*.ng,*.sht,*.shtm,*.shtml}] ij_smart_tabs = true ij_html_add_new_line_before_tags = body,div,p,form,h1,h2,h3 @@ -491,7 +1346,7 @@ ij_html_block_comment_add_space = false ij_html_block_comment_at_first_column = true ij_html_do_not_align_children_of_min_lines = 0 ij_html_do_not_break_if_inline_tags = title,h1,h2,h3,h4,h5,h6,p -ij_html_do_not_indent_children_of_tags = none +ij_html_do_not_indent_children_of_tags = ij_html_enforce_quotes = false ij_html_inline_tags = a,abbr,acronym,b,basefont,bdo,big,br,cite,cite,code,dfn,em,font,i,img,input,kbd,label,q,s,samp,select,small,span,strike,strong,sub,sup,textarea,tt,u,var ij_html_keep_blank_lines = 0 @@ -510,19 +1365,56 @@ ij_html_space_around_equality_in_attribute = false ij_html_space_inside_empty_tag = true ij_html_text_wrap = off +[{*.http,*.rest}] +indent_size = 0 +ij_continuation_indent_size = 4 +ij_http-request_call_parameters_wrap = normal +ij_http-request_method_parameters_wrap = split_into_lines +ij_http-request_space_before_comma = true +ij_http-request_spaces_around_assignment_operators = true + +[{*.jsf,*.jsp,*.jspf,*.tag,*.tagf,*.xjsp}] +ij_smart_tabs = true +ij_jsp_jsp_prefer_comma_separated_import_list = false +ij_jsp_keep_indents_on_empty_lines = true + +[{*.jspx,*.tagx}] +ij_smart_tabs = true +ij_jspx_keep_indents_on_empty_lines = true + [{*.markdown,*.md}] ij_smart_tabs = true ij_markdown_force_one_space_after_blockquote_symbol = true ij_markdown_force_one_space_after_header_symbol = true ij_markdown_force_one_space_after_list_bullet = true ij_markdown_force_one_space_between_words = true +ij_markdown_format_tables = true +ij_markdown_insert_quote_arrows_on_wrap = true ij_markdown_keep_indents_on_empty_lines = true +ij_markdown_keep_line_breaks_inside_text_blocks = true ij_markdown_max_lines_around_block_elements = 1 ij_markdown_max_lines_around_header = 1 ij_markdown_max_lines_between_paragraphs = 1 ij_markdown_min_lines_around_block_elements = 1 ij_markdown_min_lines_around_header = 1 ij_markdown_min_lines_between_paragraphs = 1 +ij_markdown_wrap_text_if_long = true +ij_markdown_wrap_text_inside_blockquotes = true + +[{*.pb,*.textproto}] +indent_size = 2 +indent_style = space +tab_width = 2 +ij_continuation_indent_size = 4 +ij_prototext_keep_blank_lines_in_code = 2 +ij_prototext_keep_indents_on_empty_lines = false +ij_prototext_keep_line_breaks = true +ij_prototext_space_after_colon = true +ij_prototext_space_after_comma = true +ij_prototext_space_before_colon = false +ij_prototext_space_before_comma = false +ij_prototext_spaces_within_braces = true +ij_prototext_spaces_within_brackets = false [{*.properties,spring.handlers,spring.schemas}] ij_properties_align_group_field_declarations = false @@ -530,3 +1422,23 @@ ij_properties_keep_blank_lines = true ij_properties_key_value_delimiter = equals ij_properties_spaces_around_key_value_delimiter = true +[{*.qute.htm,*.qute.html,*.qute.json,*.qute.txt,*.qute.yaml,*.qute.yml}] +indent_style = space +ij_qute_keep_indents_on_empty_lines = false + +[{*.toml,Cargo.lock,Cargo.toml.orig,Gopkg.lock,Pipfile,poetry.lock}] +indent_style = space +ij_toml_keep_indents_on_empty_lines = false + +[{*.yaml,*.yml}] +indent_size = 2 +ij_yaml_align_values_properties = do_not_align +ij_yaml_autoinsert_sequence_marker = true +ij_yaml_block_mapping_on_new_line = false +ij_yaml_indent_sequence_value = true +ij_yaml_keep_indents_on_empty_lines = true +ij_yaml_keep_line_breaks = true +ij_yaml_sequence_on_new_line = false +ij_yaml_space_before_colon = false +ij_yaml_spaces_within_braces = true +ij_yaml_spaces_within_brackets = true diff --git a/.gitignore b/.gitignore index e23a3f5..f9ff432 100644 --- a/.gitignore +++ b/.gitignore @@ -4,8 +4,6 @@ .vscode/ .gradle/ .settings/ -/src/test/java/test/* -/src/test/resources/test/* #build /build/ diff --git a/build.gradle b/build.gradle index f0041ee..deb0e57 100644 --- a/build.gradle +++ b/build.gradle @@ -3,6 +3,7 @@ plugins { id 'java-library' id 'application' id 'maven-publish' + id "io.github.ysohda.scalatest" version "0.32.1" id 'com.github.johnrengelman.shadow' version '8.1.1' id 'com.github.gmazzo.buildconfig' version '4.1.2' id 'org.ajoberstar.grgit' version '5.2.0' @@ -84,8 +85,10 @@ dependencies { implementation "com.squareup.okhttp3:okhttp:${lib_okhttp_v}" implementation "com.google.code.gson:gson:${lib_gson_v}" - testImplementation platform("org.junit:junit-bom:${lib_junit_v}") - testImplementation "org.junit.jupiter:junit-jupiter" + testImplementation "org.scalatest:scalatest_$proj_scala_api:${lib_scalatest_v}" + testImplementation "org.scalatest:scalatest-freespec_$proj_scala_api:${lib_scalatest_v}" + testRuntimeOnly "org.scala-lang.modules:scala-xml_$proj_scala_api:${lib_scalamodule_xml_v}" + testRuntimeOnly 'com.vladsch.flexmark:flexmark-all:0.64.6' // for generating HTML report // required by gradle-scalatest plugin } @@ -108,14 +111,18 @@ tasks.withType(ScalaCompile).configureEach { scalaCompileOptions.additionalParameters.add "-language:postfixOps" // scalaCompileOptions.additionalParameters.add("-Yexplicit-nulls") - +// scalaCompileOptions.additionalParameters.add "-language:experimental.saferExceptions" + } +tasks.withType(Javadoc).configureEach { + options.encoding = proj_file_encoding.name() +} + +//tasks.withType(ScalaDoc).configureEach { +//} + test { - useJUnitPlatform() - testLogging { - events "passed", "skipped", "failed" - } } application { @@ -152,7 +159,7 @@ shadowJar { } -@SuppressWarnings("all") +@SuppressWarnings('GrMethodMayBeStatic') boolean isCleanBuild () { if (grgit == null) return false Set changes = grgit.status().unstaged.allChanges + grgit.status().staged.allChanges diff --git a/gradle.properties b/gradle.properties index 9ce1455..1a9ee69 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,13 +8,14 @@ MORNY_COMMIT_PATH = https://github.com/Eyre-S/Coeur-Morny-Cono/commit/%s VERSION = 1.0.0-RC4 USE_DELTA = true -VERSION_DELTA = scalaport3 +VERSION_DELTA = scalaport4 CODENAME = beiping # dependencies lib_spotbugs_v = 4.7.3 +lib_scalamodule_xml_v = 2.2.0 lib_messiva_v = 0.1.1 lib_resourcetools_v = 0.2.2 @@ -24,4 +25,4 @@ lib_javatelegramapi_v = 6.2.0 lib_okhttp_v = 4.11.0 lib_gson_v = 2.10.1 -lib_junit_v = 5.10.0 +lib_scalatest_v = 3.2.17 diff --git a/src/main/java/cc/sukazyo/cono/morny/util/BiliTool.java b/src/main/java/cc/sukazyo/cono/morny/util/BiliTool.java deleted file mode 100644 index a7df8bc..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/util/BiliTool.java +++ /dev/null @@ -1,98 +0,0 @@ -package cc.sukazyo.cono.morny.util; - -import javax.annotation.Nonnegative; -import javax.annotation.Nonnull; -import java.util.HashMap; -import java.util.Map; - -public class BiliTool { - - private static final long V_CONV_XOR = 177451812L; - private static final long V_CONV_ADD = 8728348608L; - private static final char[] BV_TABLE = "fZodR9XQDSUm21yCkr6zBqiveYah8bt4xsWpHnJE7jL5VG3guMTKNPAwcF".toCharArray(); - private static final int TABLE_INT = BV_TABLE.length; - private static final Map BV_TABLE_REVERSED = new HashMap<>(); - static { for (int i = 0; i < BV_TABLE.length; i++) BV_TABLE_REVERSED.put(BV_TABLE[i], i); } - private static final char[] BV_TEMPLATE = "1 4 1 7 ".toCharArray(); - private static final int[] BV_TEMPLATE_FILTER = new int[]{9, 8, 1, 6, 2, 4}; - - public static class IllegalFormatException extends RuntimeException { - - private IllegalFormatException (String bv, String reason) { - super("`%s` is not a valid 10 digits base58 BV id: %s".formatted(bv, reason)); - } - - private IllegalFormatException (String bv, int length) { - this(bv, "length is %d.".formatted(length)); - } - - private IllegalFormatException (String bv, char c, int location) { - this(bv, "char `%s` is not in base58 char table (in position %d)".formatted(c, location)); - } - - } - - /** - * Convert a Bilibili AV video id format to BV id format. - *

- * the AV id is a number; the BV id is a special base58 number, it shows as String in programming.
- * eg:
- * while the link {@code https://www.bilibili.com/video/BV17x411w7KC/} - * shows the same with {@code https://www.bilibili.com/video/av170001/}, - * the AV id is {@code 170001}, the BV id is {@code 17x411w7KC} - *

- * for now , the BV id has 10 digits. - * the method available while the av-id < 2^27, while it theoretically available when the av-id < 2^30. - *

- * this method allows input only 10 digits base58 BV id, if the input is not formatted by this method, it will throw - * an Exception. - * - * @see mcfx的回复: 如何看待 2020 年 3 月 23 日哔哩哔哩将稿件的「av 号」变更为「BV 号」? - * - * @param bv the BV id, a string in (a special) base58 number format, without "BV" prefix. - * @return the AV id corresponding to this bv id in Bilibili, formatted as a number. - * @throws IllegalFormatException if the input BV id is not the 10 digits base58 String. - */ - @Nonnegative - public static long toAv (@Nonnull String bv) throws IllegalFormatException { - long av = 0; - if (bv.length() != 10) - throw new IllegalFormatException(bv, bv.length()); - for (int i = 0; i < BV_TEMPLATE_FILTER.length; i++) { - final Integer tableToken = BV_TABLE_REVERSED.get(bv.charAt(BV_TEMPLATE_FILTER[i])); - if (tableToken == null) - throw new IllegalFormatException(bv, bv.charAt(BV_TEMPLATE_FILTER[i]), BV_TEMPLATE_FILTER[i]); - av += tableToken * Math.pow(TABLE_INT,i); - } - return (av-V_CONV_ADD)^V_CONV_XOR; - } - - /** - * Convert a Bilibili BV video id format to AV id format. - *

- * the AV id is a number; the BV id is a special base58 number, it shows as String in programming.
- * eg:
- * while the link {@code https://www.bilibili.com/video/BV17x411w7KC/} - * shows the same with {@code https://www.bilibili.com/video/av170001/}, - * the AV id is {@code 170001}, the BV id is {@code 17x411w7KC} - *

- * for now , the BV id has 10 digits. - * the method available while the av-id < 2^27, while it theoretically available when the av-id < 2^30. - * - * @see mcfx的回复: 如何看待 2020 年 3 月 23 日哔哩哔哩将稿件的「av 号」变更为「BV 号」? - * - * @param av the (base10) AV id. - * @return the AV id corresponding to this bv id in Bilibili, - * as a (special) base 58 number format without "BV" prefix. - */ - @Nonnull - public static String toBv (@Nonnegative long av) { - av = (av^V_CONV_XOR)+V_CONV_ADD; - final char[] bv = BV_TEMPLATE.clone(); - for (int i = 0; i < BV_TEMPLATE_FILTER.length; i++) { - bv[BV_TEMPLATE_FILTER[i]] = BV_TABLE[(int)(Math.floor(av/(Math.pow(TABLE_INT, i)))%TABLE_INT)]; - } - return String.copyValueOf(bv); - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/util/CommonConvert.java b/src/main/java/cc/sukazyo/cono/morny/util/CommonConvert.java deleted file mode 100644 index 907cdd5..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/util/CommonConvert.java +++ /dev/null @@ -1,61 +0,0 @@ -package cc.sukazyo.cono.morny.util; - -import javax.annotation.Nonnegative; -import javax.annotation.Nonnull; - -/** - * 进行简单类型转换等工作的类. - */ -public class CommonConvert { - - /** - * 将字节数组转换成 hex 字符串. - * @param b 字节数组 - * @return String 格式的字节数组的 hex 值(每个字节当中没有分隔符) - * @see #byteToHex(byte) - */ - @Nonnull - public static String byteArrayToHex(@Nonnull byte[] b){ - StringBuilder sb = new StringBuilder(); - for (byte value : b) { - sb.append(byteToHex(value)); - } - return sb.toString(); - } - - /** - * 将一个字节转换成十六进制 hex 字符串. - * @param b 字节值 - * @return String 格式的字节的 hex 值(小写) - */ - @Nonnull - public static String byteToHex(byte b) { - final String hex = Integer.toHexString(b & 0xff); - return hex.length()<2?"0"+hex:hex; - } - - /** - * 将一个字符串数组按照一定规则连接. - *

- * 连接的方式类似于"数据1+分隔符+数据2+分隔符+...+数据n-1+分隔符+数据n" - * - * @param array 需要进行连接的字符串数组,数组中每一个元素会是一个数据 - * @param connector 在每两个传入数据中插入的分隔符 - * @param startIndex 从传入的数据组中的哪一个位置开始(第一个元素的位置是 {@code 0}) - * @param stopIndex 从传入的数据组中的哪一个位置停止(元素位置计算方式同上) - * @return 连接好的字符串 - */ - @Nonnull - public static String stringsConnecting ( - @Nonnull String[] array, @Nonnull String connector, @Nonnegative int startIndex, @Nonnegative int stopIndex - ) { - final StringBuilder builder = new StringBuilder(); - for (int i = startIndex; i < stopIndex; i++) { - builder.append(array[i]); - builder.append(connector); - } - builder.append(array[stopIndex]); - return builder.toString(); - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/util/CommonEncrypt.java b/src/main/java/cc/sukazyo/cono/morny/util/CommonEncrypt.java deleted file mode 100644 index 0e9c35d..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/util/CommonEncrypt.java +++ /dev/null @@ -1,144 +0,0 @@ -package cc.sukazyo.cono.morny.util; - -import javax.annotation.Nonnull; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Base64; - -/** - * 用于数据加密或编解码的工具类. - *

- * 出于 java std 中 Base64 的 {@link Base64.Encoder encode}/{@link Base64.Decoder decode} 十分好用,在此不再进行包装。 - */ -public class CommonEncrypt { - - /** - * 在使用加密算法处理字符串时默认会使用的字符串编码. - *

- * Morny 使用 UTF-8 编码因为这是一般而言加解密工具的默认行为 - */ - public static final Charset ENCRYPT_STANDARD_CHARSET = StandardCharsets.UTF_8; - - @Nonnull - private static byte[] hashAsJavaMessageDigest(String algorithm, @Nonnull byte[] data) { - try { - return MessageDigest.getInstance(algorithm).digest(data); - } catch (NoSuchAlgorithmException e) { - throw new IllegalStateException(e); - } - } - - /** - * 取得数据的 md5 散列值. - * - * @param data byte 数组形式的数据体 - * @return 二进制(byte数组)格式的数据的 md5 散列值 - */ - @Nonnull - public static byte[] hashMd5 (@Nonnull byte[] data) { - return hashAsJavaMessageDigest("md5", data); - } - - /** - * 取得一个字符串的 md5 散列值. - *

- * 输入的字符串将会以 {@link #ENCRYPT_STANDARD_CHARSET 默认的 UTF-8} 编码进行解析 - * - * @param originString 要进行散列的字符串 - * @return 二进制(byte数组)格式的 md5 散列值 - */ - @Nonnull - public static byte[] hashMd5 (String originString) { - return hashMd5(originString.getBytes(ENCRYPT_STANDARD_CHARSET)); - } - - /** - * 取得数据的 sha1 散列值. - * - * @param data byte 数组形式的数据体 - * @return 二进制(byte数组)格式的数据的 sha1 散列值 - */ - @Nonnull - public static byte[] hashSha1 (@Nonnull byte[] data) { - return hashAsJavaMessageDigest("sha1", data); - } - - /** - * 取得一个字符串的 sha1 散列值. - *

- * 输入的字符串将会以 {@link #ENCRYPT_STANDARD_CHARSET 默认的 UTF-8} 编码进行解析 - * - * @param originString 要进行散列的字符串 - * @return 二进制(byte数组)格式的 sha1 散列值 - */ - @Nonnull - public static byte[] hashSha1 (String originString) { - return hashMd5(originString.getBytes(ENCRYPT_STANDARD_CHARSET)); - } - - /** - * 取得数据的 sha256 散列值. - * - * @param data byte 数组形式的数据体 - * @return 二进制(byte数组)格式的数据的 sha256 散列值 - */ - @Nonnull - public static byte[] hashSha256 (@Nonnull byte[] data) { - return hashAsJavaMessageDigest("sha256", data); - } - - /** - * 取得一个字符串的 sha256 散列值. - *

- * 输入的字符串将会以 {@link #ENCRYPT_STANDARD_CHARSET 默认的 UTF-8} 编码进行解析 - * - * @param originString 要进行散列的字符串 - * @return 二进制(byte数组)格式的 sha256 散列值 - */ - @Nonnull - public static byte[] hashSha256 (String originString) { - return hashMd5(originString.getBytes(ENCRYPT_STANDARD_CHARSET)); - } - - /** - * 取得数据的 sha512 散列值. - * - * @param data byte 数组形式的数据体 - * @return 二进制(byte数组)格式的数据的 sha512 散列值 - */ - @Nonnull - public static byte[] hashSha512 (@Nonnull byte[] data) { - return hashAsJavaMessageDigest("md5", data); - } - - /** - * 取得一个字符串的 sha512 散列值. - *

- * 输入的字符串将会以 {@link #ENCRYPT_STANDARD_CHARSET 默认的 UTF-8} 编码进行解析 - * - * @param originString 要进行散列的字符串 - * @return 二进制(byte数组)格式的 sha512 散列值 - */ - @Nonnull - public static byte[] hashSha512 (String originString) { - return hashMd5(originString.getBytes(ENCRYPT_STANDARD_CHARSET)); - } - - @Nonnull - public static String base64FilenameLint (String inputName) { - if (inputName.endsWith(".b64")) { - return inputName.substring(0, inputName.length()-".b64".length()); - } else if (inputName.endsWith(".b64.txt")) { - return inputName.substring(0, inputName.length()-".b64.txt".length()); - } else if (inputName.endsWith(".base64")) { - return inputName.substring(0, inputName.length()-".base64".length()); - } else if (inputName.endsWith(".base64.txt")) { - return inputName.substring(0, inputName.length()-".base64.txt".length()); - } else { - return inputName; - } - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/util/CommonFormat.java b/src/main/java/cc/sukazyo/cono/morny/util/CommonFormat.java deleted file mode 100644 index 0598ba6..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/util/CommonFormat.java +++ /dev/null @@ -1,30 +0,0 @@ -package cc.sukazyo.cono.morny.util; - -import java.time.Instant; -import java.time.LocalDateTime; -import java.time.ZoneId; -import java.time.ZoneOffset; -import java.time.format.DateTimeFormatter; - -public class CommonFormat { - - public static final String DATE_TIME_PATTERN_FULL_MILLIS = "yyyy-MM-dd HH:mm:ss:SSS"; - - public static String formatDate (long timestamp, int utcOffset) { - return DateTimeFormatter.ofPattern(DATE_TIME_PATTERN_FULL_MILLIS).format(LocalDateTime.ofInstant( - Instant.ofEpochMilli(timestamp), - ZoneId.ofOffset("UTC", ZoneOffset.ofHours(utcOffset)) - )); - } - - public static String formatDuration (long duration) { - StringBuilder sb = new StringBuilder(); - if (duration > 1000 * 60 * 60 * 24) sb.append(duration / (1000*60*60*24)).append("d "); - if (duration > 1000 * 60 * 60) sb.append(duration / (1000*60*60) % 24).append("h "); - if (duration > 1000 * 60) sb.append(duration / (1000*60) % 60).append("min "); - if (duration > 1000) sb.append(duration / 1000 % 60).append("s "); - sb.append(duration % 1000).append("ms"); - return sb.toString(); - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/util/CommonRandom.java b/src/main/java/cc/sukazyo/cono/morny/util/CommonRandom.java deleted file mode 100644 index 22c9812..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/util/CommonRandom.java +++ /dev/null @@ -1,44 +0,0 @@ -package cc.sukazyo.cono.morny.util; - -import javax.annotation.Nonnegative; -import java.util.concurrent.ThreadLocalRandom; - -public class CommonRandom { - - /** - * 通过 {@link ThreadLocalRandom} 以指定的一定几率返回 true. - * @param probability 一个正整数,决定在样本空间中有多大的可能性为 true。 - * @param base 一个正整数,决定样本空间有多大。 - * @return 有 {@code base} 分之 {@code probability} 的几率,返回值为 {@link true}. - * 如果 {@code probability} 大于 {@code base},也就是为 true 的可能性大于 100%,则会永远为 true。 - * @throws IllegalArgumentException - * 当参数 base 或是 probability 不为正整数时 - * @since 1.0.0-RC3.2 - */ - public static boolean probabilityTrue (@Nonnegative int probability, @Nonnegative int base) { - if (probability < 1) throw new IllegalArgumentException("the probability must be a positive value!"); - if (base < 1) throw new IllegalArgumentException("the probability base must be a positive value!"); - return probability > ThreadLocalRandom.current().nextInt(base); - } - - /** - * 以一定几率返回 true. - * @return {@code probabilityIn} 分之 {@link 1} 的几率为 {@link true}. - * @see #probabilityTrue(int, int) - * @since 1.0.0-RC3.2 - */ - public static boolean probabilityTrue (@Nonnegative int probabilityIn) { - return (probabilityTrue(1, probabilityIn)); - } - - /** - * 通过 {@link ThreadLocalRandom} 实现的随机 boolean 取值. - * @return 随机的 {@link true} 或 {@link false},各占(近似)一半可能性. - * @see ThreadLocalRandom#nextBoolean() - * @since 1.0.0-RC3.2 - */ - public static boolean iif () { - return ThreadLocalRandom.current().nextBoolean(); - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/util/FileUtils.java b/src/main/java/cc/sukazyo/cono/morny/util/FileUtils.java deleted file mode 100644 index 57ff657..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/util/FileUtils.java +++ /dev/null @@ -1,28 +0,0 @@ -package cc.sukazyo.cono.morny.util; - -import javax.annotation.Nonnull; -import java.io.FileInputStream; -import java.io.IOException; -import java.math.BigInteger; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - -public class FileUtils { - - @Nonnull - public static String getMD5Three (@Nonnull String path) throws IOException, NoSuchAlgorithmException { - final BigInteger bi; - final byte[] buffer = new byte[8192]; - int len; - final MessageDigest md = MessageDigest.getInstance("MD5"); - final FileInputStream fis = new FileInputStream(path); - while ((len = fis.read(buffer)) != -1) { - md.update(buffer, 0, len); - } - fis.close(); - final byte[] b = md.digest(); - bi = new BigInteger(1, b); - return bi.toString(16); - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/util/OkHttpPublic.java b/src/main/java/cc/sukazyo/cono/morny/util/OkHttpPublic.java deleted file mode 100644 index fb6b32a..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/util/OkHttpPublic.java +++ /dev/null @@ -1,13 +0,0 @@ -package cc.sukazyo.cono.morny.util; - -import okhttp3.MediaType; - -public class OkHttpPublic { - - public static class MediaTypes { - - public static final MediaType JSON = MediaType.get("application/json; charset=utf-8"); - - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/util/UniversalCommand.java b/src/main/java/cc/sukazyo/cono/morny/util/UniversalCommand.java deleted file mode 100644 index 2bf2e8e..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/util/UniversalCommand.java +++ /dev/null @@ -1,49 +0,0 @@ -package cc.sukazyo.cono.morny.util; - -import javax.annotation.Nonnull; -import java.util.ArrayList; - -public class UniversalCommand { - - @Nonnull - public static String[] format (@Nonnull String com) { - - final ArrayList arr = new ArrayList<>(); - - final StringBuilder tmp = new StringBuilder(); - final char[] coma = com.toCharArray(); - for (int i = 0; i < coma.length; i++) { - if (coma[i] == ' ') { - if (!tmp.toString().equals("")) { arr.add(tmp.toString()); } - tmp.setLength(0); - } else if (coma[i] == '"') { - while (true) { - i++; - if (i >= coma.length) { - break; - } else if (coma[i] == '"') { - break; - } else if (coma[i] == '\\' && i+1 < coma.length && (coma[i+1] == '"' || coma[i+1] == '\\')) { - i++; - tmp.append(coma[i]); - } else { - tmp.append(coma[i]); - } - } - } else if (coma[i] == '\\' && i+1 < coma.length && (coma[i+1] == ' ' || coma[i+1] == '"' || coma[i+1] == '\\')) { - i++; - tmp.append(coma[i]); - } else { - tmp.append(coma[i]); - } - } - if (!tmp.toString().equals("")) { arr.add(tmp.toString()); } - tmp.setLength(0); - - final String[] out = new String[arr.size()]; - arr.toArray(out); - return out; - - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/InputCommand.java b/src/main/java/cc/sukazyo/cono/morny/util/tgapi/InputCommand.java deleted file mode 100644 index a62a3c9..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/InputCommand.java +++ /dev/null @@ -1,66 +0,0 @@ -package cc.sukazyo.cono.morny.util.tgapi; - -import cc.sukazyo.cono.morny.util.UniversalCommand; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.util.Arrays; - -public class InputCommand { - - - private final String target; - private final String command; - private final String[] args; - - private InputCommand (@Nullable String target, @Nonnull String command, @Nonnull String[] args) { - this.target = target; - this.command = command; - this.args = args; - } - - public InputCommand (@Nonnull String[] inputArray) { - this(parseInputArray(inputArray)); - } - - public InputCommand (@Nonnull String input) { - this(UniversalCommand.format(input)); - } - - public InputCommand (@Nonnull InputCommand source) { - this(source.target, source.command, source.args); - } - - public static InputCommand parseInputArray (@Nonnull String[] inputArray) { - final String[] cx = inputArray[0].split("@", 2); - final String[] args = new String[inputArray.length-1]; - System.arraycopy(inputArray, 1, args, 0, inputArray.length - 1); - return new InputCommand(cx.length == 1 ? null : cx[1], cx[0], args); - } - - @Nullable - public String getTarget () { - return target; - } - - @Nonnull - public String getCommand () { - return command; - } - - @Nonnull - public String[] getArgs () { - return args; - } - - public boolean hasArgs () { - return args.length != 0; - } - - @Override - @Nonnull - public String toString() { - return String.format("{{%s}@{%s}#{%s}}", command, target, Arrays.toString(args)); - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/Standardize.java b/src/main/java/cc/sukazyo/cono/morny/util/tgapi/Standardize.java deleted file mode 100644 index ae3efa3..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/Standardize.java +++ /dev/null @@ -1,7 +0,0 @@ -package cc.sukazyo.cono.morny.util.tgapi; - -public class Standardize { - - public static final int CHANNEL_SPEAKER_MAGIC_ID = 136817688; - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/event/EventRuntimeException.java b/src/main/java/cc/sukazyo/cono/morny/util/tgapi/event/EventRuntimeException.java deleted file mode 100644 index 368d3b9..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/event/EventRuntimeException.java +++ /dev/null @@ -1,35 +0,0 @@ -package cc.sukazyo.cono.morny.util.tgapi.event; - -import com.pengrad.telegrambot.response.BaseResponse; - -public class EventRuntimeException extends RuntimeException { - - public EventRuntimeException () { - super(); - } - - public EventRuntimeException (String message) { - super(message); - } - - public static class ActionFailed extends EventRuntimeException { - - private final BaseResponse response; - - public ActionFailed (BaseResponse response) { - super(); - this.response = response; - } - - public ActionFailed (String message, BaseResponse response) { - super(message); - this.response = response; - } - - public BaseResponse getResponse() { - return response; - } - - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/MsgEscape.java b/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/MsgEscape.java deleted file mode 100644 index 06703a4..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/MsgEscape.java +++ /dev/null @@ -1,15 +0,0 @@ -package cc.sukazyo.cono.morny.util.tgapi.formatting; - -import javax.annotation.Nonnull; - -public class MsgEscape { - - @Nonnull - public static String escapeHtml (@Nonnull String raw) { - raw = raw.replaceAll("&", "&"); - raw = raw.replaceAll("<", "<"); - raw = raw.replaceAll(">", ">"); - return raw; - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/NamedUtils.java b/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/NamedUtils.java deleted file mode 100644 index b046f30..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/NamedUtils.java +++ /dev/null @@ -1,18 +0,0 @@ -package cc.sukazyo.cono.morny.util.tgapi.formatting; - -import cc.sukazyo.cono.morny.util.CommonConvert; -import cc.sukazyo.cono.morny.util.CommonEncrypt; - -import javax.annotation.Nonnull; - -public class NamedUtils { - - public static String inlineIds (@Nonnull String tag) { - return inlineIds(tag, ""); - } - - public static String inlineIds (@Nonnull String tag, @Nonnull String taggedData) { - return CommonConvert.byteArrayToHex(CommonEncrypt.hashMd5(tag+taggedData)); - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToString.java b/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToString.java deleted file mode 100644 index 027f515..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToString.java +++ /dev/null @@ -1,21 +0,0 @@ -package cc.sukazyo.cono.morny.util.tgapi.formatting; - -import com.pengrad.telegrambot.model.Chat; -import com.pengrad.telegrambot.model.Message; -import com.pengrad.telegrambot.model.User; - -public class TGToString { - - public static TGToStringFromChat as (Chat chat) { - return new TGToStringFromChat(chat); - } - - public static TGToStringFromUser as (User user) { - return new TGToStringFromUser(user); - } - - public static TGToStringFromMessage as (Message message) { - return new TGToStringFromMessage(message); - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromChat.java b/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromChat.java deleted file mode 100644 index e327279..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromChat.java +++ /dev/null @@ -1,60 +0,0 @@ -package cc.sukazyo.cono.morny.util.tgapi.formatting; - -import com.pengrad.telegrambot.model.Chat; - -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) { - this.data = chat; - } - - public String toStringFullNameId() { - if (data.title() == null) { - throw new IllegalArgumentException("Cannot format private chat to group Name+Id format."); - } - return (data.username() == null) ? - (String.format("%s [%d]", data.title(), data.id())) : - (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/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromMessage.java b/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromMessage.java deleted file mode 100644 index 08b2d94..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromMessage.java +++ /dev/null @@ -1,27 +0,0 @@ -package cc.sukazyo.cono.morny.util.tgapi.formatting; - -import com.pengrad.telegrambot.model.Message; - -import javax.annotation.Nonnull; - -public class TGToStringFromMessage extends TGToString { - - @Nonnull - private final Message message; - - public TGToStringFromMessage (@Nonnull Message message) { this.message = message; } - - @Nonnull - public String getSenderFirstNameRefHtml () { - return message.senderChat()==null ? TGToString.as(message.from()).firstnameRefHtml() : String.format( - "%s", - message.senderChat().id(), - MsgEscape.escapeHtml(message.senderChat().title()) - ); - } - - public long getSenderId () { - return message.senderChat()==null ? message.from().id() : message.senderChat().id(); - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromUser.java b/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromUser.java deleted file mode 100644 index fa41d3c..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TGToStringFromUser.java +++ /dev/null @@ -1,53 +0,0 @@ -package cc.sukazyo.cono.morny.util.tgapi.formatting; - -import com.pengrad.telegrambot.model.User; - -public class TGToStringFromUser { - - private final User data; - - public TGToStringFromUser (User user) { - this.data = user; - } - - public String fullname () { - return data.firstName() + (data.lastName()==null ? "" : " "+data.lastName()); - } - - public String fullnameRefHtml () { - return String.format( - "%s", - data.id(), - MsgEscape.escapeHtml(fullname()) - ); - } - - public String fullnameRefMarkdown () { - return String.format( - "[%s](tg://user?id=%d)", - fullname(), - data.id() - ); - } - - public String firstnameRefHtml () { - return String.format( - "%s", - data.id(), - MsgEscape.escapeHtml(data.firstName()) - ); - } - - public String firstnameRefMarkdown () { - return String.format( - "[%s](tg://user?id=%d)", - data.firstName(), - data.id() - ); - } - - public String toStringLogTag () { - return (data.username()==null ? fullname()+" " : "@"+data.username()) + "[" + data.id() + "]"; - } - -} diff --git a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramUserInformation.java b/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramUserInformation.java deleted file mode 100644 index e1703e4..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramUserInformation.java +++ /dev/null @@ -1,85 +0,0 @@ -package cc.sukazyo.cono.morny.util.tgapi.formatting; - -import com.pengrad.telegrambot.model.User; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -import okhttp3.ResponseBody; - -import javax.annotation.Nullable; -import java.io.IOException; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import static cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml; - -public class TelegramUserInformation { - - public static final String DC_QUERY_SOURCE_SITE = "https://t.me/"; - public static final Pattern DC_QUERY_PROCESSOR_REGEX = Pattern.compile("(cdn[1-9]).tele(sco.pe|gram-cdn.org)"); - - private static final OkHttpClient httpClient = new OkHttpClient(); - - @Nullable - public static String getDataCenterFromUsername (String username) { - final Request request = new Request.Builder().url(DC_QUERY_SOURCE_SITE + username).build(); - try (Response response = httpClient.newCall(request).execute()) { - final ResponseBody body = response.body(); - if (body == null) return "empty upstream response"; - final Matcher matcher = DC_QUERY_PROCESSOR_REGEX.matcher(body.string()); - if (matcher.find()) { - return matcher.group(1); - } - } catch (IOException e) { - return e.getMessage(); - } - return null; - } - - public static String informationOutputHTML (User user) { - - final StringBuilder userInformation = new StringBuilder(); - userInformation.append(String.format( - """ - userid : - - %d""", - user.id() - )); - if (user.username() == null) { - userInformation.append("\nusername : null\ndatacenter : null"); - } else { - userInformation.append(String.format( - """ - - username : - - %s""", - escapeHtml(user.username()) - )); - // 依赖 username 的 datacenter 查询 - final String dataCenter = getDataCenterFromUsername(user.username()); - if (dataCenter == null) { userInformation.append("\ndatacenter : null"); } - else { userInformation.append(String.format("\ndatacenter : %s", escapeHtml(dataCenter))); } - } - userInformation.append(String.format( - """ - - display name : - - %s%s""", - escapeHtml(user.firstName()), - user.lastName()==null ? "" : String.format("\n- %s", escapeHtml(user.lastName())) - )); - if (user.languageCode() != null) { - userInformation.append(String.format( - """ - - language-code : - - %s""", - escapeHtml(user.languageCode()) - )); - } - - return userInformation.toString(); - - } - -} diff --git a/src/main/scala/cc/sukazyo/cono/morny/MornyCoeur.scala b/src/main/scala/cc/sukazyo/cono/morny/MornyCoeur.scala index 6bfad74..1860236 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/MornyCoeur.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/MornyCoeur.scala @@ -2,11 +2,11 @@ package cc.sukazyo.cono.morny import cc.sukazyo.cono.morny.bot.command.MornyCommands import cc.sukazyo.cono.morny.daemon.MornyDaemons -import cc.sukazyo.cono.morny.util.tgapi.ExtraAction import cc.sukazyo.cono.morny.Log.{exceptionLog, logger} import cc.sukazyo.cono.morny.MornyCoeur.THREAD_MORNY_EXIT import cc.sukazyo.cono.morny.bot.api.TelegramUpdatesListener import cc.sukazyo.cono.morny.bot.event.MornyEventListeners +import cc.sukazyo.cono.morny.util.tgapi.ExtraAction import com.pengrad.telegrambot.TelegramBot import com.pengrad.telegrambot.request.GetMe diff --git a/src/main/scala/cc/sukazyo/cono/morny/MornySystem.scala b/src/main/scala/cc/sukazyo/cono/morny/MornySystem.scala index 69fb74f..7e052eb 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/MornySystem.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/MornySystem.scala @@ -1,13 +1,13 @@ package cc.sukazyo.cono.morny import cc.sukazyo.cono.morny.internal.BuildConfigField +import cc.sukazyo.cono.morny.Log.{exceptionLog, logger} +import cc.sukazyo.cono.morny.daemon.MornyReport import cc.sukazyo.cono.morny.util.FileUtils import java.io.IOException import java.net.URISyntaxException import java.security.NoSuchAlgorithmException -import Log.{exceptionLog, logger} -import cc.sukazyo.cono.morny.daemon.MornyReport object MornySystem { 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 index 9eed851..98b7852 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/api/EventListenerManager.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/api/EventListenerManager.scala @@ -1,9 +1,9 @@ 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 cc.sukazyo.cono.morny.util.tgapi.event.EventRuntimeException import com.google.gson.GsonBuilder import com.pengrad.telegrambot.model.Update @@ -65,7 +65,7 @@ object EventListenerManager { case actionFailed: EventRuntimeException.ActionFailed => errorMessage ++= "\ntg-api action: response track: " errorMessage ++= (GsonBuilder().setPrettyPrinting().create().toJson( - actionFailed.getResponse + actionFailed.response ) indent 4) ++= "\n" case _ => logger error errorMessage.toString 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 975c47b..f1faef6 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 @@ -4,10 +4,10 @@ import cc.sukazyo.cono.morny.Log.logger import cc.sukazyo.cono.morny.MornyCoeur import cc.sukazyo.cono.morny.daemon.MornyReport import cc.sukazyo.cono.morny.data.TelegramStickers -import cc.sukazyo.cono.morny.util.CommonConvert.byteArrayToHex +import cc.sukazyo.cono.morny.util.tgapi.InputCommand import cc.sukazyo.cono.morny.util.CommonEncrypt import cc.sukazyo.cono.morny.util.CommonEncrypt.* -import cc.sukazyo.cono.morny.util.tgapi.InputCommand +import cc.sukazyo.cono.morny.util.ConvertByteHex.toHex import com.pengrad.telegrambot.model.{PhotoSize, Update} import com.pengrad.telegrambot.model.request.ParseMode import com.pengrad.telegrambot.request.{GetFile, SendDocument, SendMessage, SendSticker} @@ -16,6 +16,7 @@ import java.io.IOException import java.util.Base64 import scala.language.postfixOps +/** Provides Telegram Command __`/encrypt`__. */ object Encryptor extends ITelegramCommand { override val name: String = "encrypt" @@ -25,12 +26,20 @@ object Encryptor extends ITelegramCommand { override def execute (using command: InputCommand, event: Update): Unit = { - val args = command.getArgs + val args = command.args + // show a simple help page if ((args isEmpty) || ((args(0) equals "l") && (args.length == 1))) echoHelp(event.message.chat.id, event.message.messageId) return + // for mod-params: + // mod-params is the args belongs to the encrypt algorithm. + // due to the algorithm is defined in the 1st (array(0)) arg, + // so the mod-params is which defined since the 2nd arg. also + // due to there's only one mod-param yet (it is uppercase), + // so the algorithm will be and must be in the 2nd arg. + /** inner function: is input `arg` means mod-param ''uppercase'' */ def _is_mod_u(arg: String): Boolean = if (arg equalsIgnoreCase "uppercase") return true if (arg equalsIgnoreCase "u") return true @@ -46,13 +55,21 @@ object Encryptor extends ITelegramCommand { return } else false - trait XEncryptable { val asByteArray: Array[Byte] } - case class XFile (data: Array[Byte], name: String) extends XEncryptable { + // BLOCK: get input + // for now, only support getting data from replied message, and + // this message CAN ONLY have texts or an universal file: if the + // universal files are not only one, only the first one can be get. + // - do NOT SUPPORT telegram inline image/video/autio yet + // - do NOT SUPPORT multi-file yet + // todo: support inline image/video/audio file and multi-files. + /** inner trait: the encryptable data abstract */ + trait XEncryptable { /** standards data to [[Array]]`[`[[Byte]]`]` for processing */ val asByteArray: Array[Byte] } + /** inner class: the [[XEncryptable]] implementation of binary([[Array]]`[`[[Byte]]`]`) data (file or something) */ + case class XFile (data: Array[Byte], name: String) extends XEncryptable: val asByteArray: Array[Byte] = data - } - case class XText (data: String) extends XEncryptable { + /** inner class: the [[XEncryptable]] implementation of [[String]] data */ + case class XText (data: String) extends XEncryptable: val asByteArray: Array[Byte] = data getBytes CommonEncrypt.ENCRYPT_STANDARD_CHARSET - } val input: XEncryptable = val _r = event.message.replyToMessage if ((_r ne null) && (_r.document ne null)) { @@ -73,9 +90,10 @@ object Encryptor extends ITelegramCommand { _photo_origin = size _photo_size = _size if (_photo_origin eq null) throw IllegalArgumentException("no photo from api.") + import cc.sukazyo.cono.morny.util.UseRandom.rand_id XFile( MornyCoeur.account getFileContent (MornyCoeur.extra exec GetFile(_photo_origin.fileId)).file, - s"photo${byteArrayToHex(hashMd5(System.currentTimeMillis toString)) substring 32-12 toUpperCase}.png" + s"photo$rand_id.png" ) } catch case e: IOException => @@ -95,19 +113,26 @@ object Encryptor extends ITelegramCommand { ).parseMode(ParseMode HTML).replyToMessageId(event.message.messageId) return } + // END BLOCK: get input - + // BLOCK: encrypt + /** inner class: encrypt result implementation of text-like (can be described as [[String]]). */ trait EXTextLike { val text: String } + /** inner class: encrypt result implementation of a file */ case class EXFile (result: Array[Byte], resultName: String) - case class EXText (result: String) extends EXTextLike { override val text:String = result } - case class EXHash (result: String) extends EXTextLike { override val text:String = result } + /** inner class: [[EXTextLike]] implementation of just normal text */ + case class EXText (text: String) extends EXTextLike + /** inner class: [[EXTextLike]] implementation of a special type: hash value */ + case class EXHash (text: String) extends EXTextLike + /** generate encrypt result by making normal encrypt: output type == input type */ def genResult_encrypt (source: XEncryptable, processor: Array[Byte]=>Array[Byte], filenameProcessor: String=>String): EXFile|EXText = { source match case x_file: XFile => EXFile(processor(x_file asByteArray), filenameProcessor(x_file.name)) - case x: XText => EXText(String(processor(x asByteArray), ENCRYPT_STANDARD_CHARSET)) + case x: XText => EXText(String(processor(x asByteArray), CommonEncrypt.ENCRYPT_STANDARD_CHARSET)) } + /** generate encrypt result by making hash: output type == hash value */ def genResult_hash (source: XEncryptable, processor: Array[Byte]=>Array[Byte]): EXHash = - val hashed = byteArrayToHex(processor(source asByteArray)) + val hashed = processor(source asByteArray) toHex; EXHash(if mod_uppercase then hashed toUpperCase else hashed) val result: EXHash|EXFile|EXText = args(0) match case "base64" | "b64" | "base64url" | "base64u" | "b64u" => @@ -126,24 +151,26 @@ object Encryptor extends ITelegramCommand { try { genResult_encrypt( input, _tool_b64d.decode, - CommonEncrypt.base64FilenameLint + CommonEncrypt.lint_base64FileName ) } catch case _: IllegalArgumentException => MornyCoeur.extra exec SendSticker( event.message.chat.id, TelegramStickers ID_404 // todo: is here better erro notify? ).replyToMessageId(event.message.messageId) return - case "md5" => genResult_hash(input, hashMd5) - case "sha1" => genResult_hash(input, hashSha1) - case "sha256" => genResult_hash(input, hashSha256) - case "sha512" => genResult_hash(input, hashSha512) + case "md5" => genResult_hash(input, MD5) + case "sha1" => genResult_hash(input, SHA1) + case "sha256" => genResult_hash(input, SHA256) + case "sha512" => genResult_hash(input, SHA512) case _ => MornyCoeur.extra exec SendSticker( event.message.chat.id, TelegramStickers ID_404 ).replyToMessageId(event.message.messageId) return; + // END BLOCK: encrypt + // output result match case _file: EXFile => MornyCoeur.extra exec SendDocument( @@ -151,7 +178,7 @@ object Encryptor extends ITelegramCommand { _file.result ).fileName(_file.resultName).replyToMessageId(event.message.messageId) case _text: EXTextLike => - import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h + import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramParseEscape.escapeHtml as h MornyCoeur.extra exec SendMessage( event.message.chat.id, s"

${h(_text.text)}
" @@ -159,6 +186,30 @@ object Encryptor extends ITelegramCommand { } + /** echo help to a specific message in a specific chat. + * + * === the help message === + * The first paragraph lists available encrypt algorithms and its alias, + * each line have one algorithm where the first name highlighted is the + * main name and following is aliases separated with `,`. + * with the separator `---`, the second paragraph lists available mods + * for algorithms, displays with the same rule of algorithms, with an extra + * italic text following describes its usage environment. + * + * when output to telegram just like: + *
+ * '''__base64__''', b64
+ * '''__base64url__''', base64u, b64u
+ * '''__base64decode__''', base64d, b64d
+ * '''__base64url-decode__''', base64ud, b64ud
+ * '''__sha1__'''
+ * '''__sha256__'''
+ * '''__sha512__'''
+ * '''__md5__'''
+ * ---
+ * '''__uppercase__''', upper, u ''(sha1/sha256/sha512/md5 only)'' + *
+ */ private def echoHelp(chat: Long, replyTo: Int): Unit = MornyCoeur.extra exec SendMessage( chat, 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 5a6d9e8..963c80a 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 @@ -1,10 +1,10 @@ package cc.sukazyo.cono.morny.bot.command import cc.sukazyo.cono.morny.MornyCoeur import cc.sukazyo.cono.morny.bot.event.OnEventHackHandle +import cc.sukazyo.cono.morny.bot.event.OnEventHackHandle.{registerHack, HackType} +import cc.sukazyo.cono.morny.data.TelegramStickers import cc.sukazyo.cono.morny.util.tgapi.InputCommand import com.pengrad.telegrambot.model.Update -import OnEventHackHandle.{HackType, registerHack} -import cc.sukazyo.cono.morny.data.TelegramStickers import com.pengrad.telegrambot.request.SendSticker import scala.language.postfixOps @@ -18,7 +18,7 @@ object EventHack extends ITelegramCommand { override def execute (using command: InputCommand, event: Update): Unit = { - val x_mode = if (command.hasArgs) command.getArgs()(0) else "" + val x_mode = if (command.args nonEmpty) command.args(0) else "" def done_ok = MornyCoeur.extra exec SendSticker( 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 7799e06..78013bd 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 @@ -18,7 +18,7 @@ object GetUsernameAndId extends ITelegramCommand { override def execute (using command: InputCommand, event: Update): Unit = { - val args = command.getArgs + val args = command.args if (args.length > 1) MornyCoeur.extra exec SendMessage( @@ -59,7 +59,7 @@ object GetUsernameAndId extends ITelegramCommand { MornyCoeur.extra exec SendMessage( event.message.chat.id, - TelegramUserInformation informationOutputHTML user + TelegramUserInformation getFormattedInformation user ).replyToMessageId(event.message.messageId()).parseMode(ParseMode HTML) } 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 b49f50d..a5d17b6 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 @@ -31,15 +31,15 @@ object IP186Query { private def query (using event: Update, command: InputCommand): Unit = { val target: String|Null = - if (command.getArgs isEmpty) + if (command.args isEmpty) if event.message.replyToMessage eq null then null else event.message.replyToMessage.text - else if (command.getArgs.length > 1) + else if (command.args.length > 1) MornyCoeur.extra exec SendMessage( event.message.chat.id, "[Unavailable] Too much arguments." ).replyToMessageId(event.message.messageId) return - else command.getArgs()(0) + else command.args(0) if (target eq null) MornyCoeur.extra exec new SendMessage( @@ -48,14 +48,15 @@ object IP186Query { ).replyToMessageId(event.message.messageId) return; + + import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramParseEscape.escapeHtml as h try { - val response = command.getCommand match + val response = command.command match case Subs.IP.cmd => IP186QueryHandler.query_ip(target) case Subs.WHOIS.cmd => IP186QueryHandler.query_whoisPretty(target) - case _ => throw IllegalArgumentException(s"Unknown 186-IP query method ${command.getCommand}") + case _ => throw IllegalArgumentException(s"Unknown 186-IP query method ${command.command}") - import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h MornyCoeur.extra exec SendMessage( event.message.chat.id, s"""${h(response.url)} @@ -64,7 +65,6 @@ object IP186Query { ).parseMode(ParseMode HTML).replyToMessageId(event.message.messageId) } catch case e: Exception => - import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h MornyCoeur.extra exec new SendMessage( event.message().chat().id(), s"""[Exception] in query: 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 index a6fbdf8..4776d68 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyCommands.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyCommands.scala @@ -1,9 +1,9 @@ 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 cc.sukazyo.cono.morny.Log.logger +import cc.sukazyo.cono.morny.util.tgapi.InputCommand import com.pengrad.telegrambot.model.{BotCommand, DeleteMyCommands, Update} import com.pengrad.telegrambot.request.{SendSticker, SetMyCommands} @@ -60,14 +60,14 @@ object MornyCommands { ) def execute (using command: InputCommand, event: Update): Boolean = { - if (commands contains command.getCommand) - commands(command.getCommand) execute; + if (commands contains command.command) + commands(command.command) execute; true else nonCommandExecutable } private def nonCommandExecutable (using command: InputCommand, event: Update): Boolean = { - if command.getTarget eq null then false + if command.target eq null then false else MornyCoeur.extra exec SendSticker( event.message.chat.id, 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 index ea310dc..80c4519 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyHellos.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyHellos.scala @@ -1,8 +1,8 @@ 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 cc.sukazyo.cono.morny.util.tgapi.InputCommand import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.request.SendSticker 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 f9c46bb..516ddd7 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 @@ -3,8 +3,8 @@ package cc.sukazyo.cono.morny.bot.command import cc.sukazyo.cono.morny.{BuildConfig, MornyAbout, MornyCoeur, MornySystem} import cc.sukazyo.cono.morny.data.{TelegramImages, TelegramStickers} import cc.sukazyo.cono.morny.util.CommonFormat.{formatDate, formatDuration} +import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramParseEscape.escapeHtml as h import cc.sukazyo.cono.morny.util.tgapi.InputCommand -import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.model.request.ParseMode import com.pengrad.telegrambot.request.{SendMessage, SendPhoto, SendSticker} @@ -30,12 +30,12 @@ object MornyInformation extends ITelegramCommand { override def execute (using command: InputCommand, event: Update): Unit = { - if (!command.hasArgs) { + if (command.args isEmpty) { echoInfo(event.message.chat.id, event.message.messageId) return } - val action: String = command.getArgs()(0) + val action: String = command.args(0) action match { case s if s startsWith Subs.STICKERS => echoStickers @@ -94,13 +94,13 @@ object MornyInformation extends ITelegramCommand { private def echoStickers (using command: InputCommand, event: Update): Unit = { val mid: String|Null = - if (command.getArgs()(0) == Subs.STICKERS) { - if (command.getArgs.length == 1) "" - else if (command.getArgs.length == 2) command.getArgs()(1) + if (command.args(0) == Subs.STICKERS) { + if (command.args.length == 1) "" + else if (command.args.length == 2) command.args(1) else null - } else if (command.getArgs.length == 1) { - if ((command.getArgs()(0) startsWith s"${Subs.STICKERS}.") || (command.getArgs()(0) startsWith s"${Subs.STICKERS}#")) { - command.getArgs()(0) substring Subs.STICKERS.length+1 + } else if (command.args.length == 1) { + if ((command.args(0) startsWith s"${Subs.STICKERS}.") || (command.args(0) startsWith s"${Subs.STICKERS}#")) { + command.args(0) substring Subs.STICKERS.length+1 } else null } else null if (mid == null) echo404 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 index 6f44f16..cad2acf 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyInformationOlds.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyInformationOlds.scala @@ -1,4 +1,5 @@ package cc.sukazyo.cono.morny.bot.command + import cc.sukazyo.cono.morny.util.tgapi.InputCommand import com.pengrad.telegrambot.model.Update 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 index bb69c48..8800c9f 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyManagers.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyManagers.scala @@ -1,15 +1,15 @@ 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 cc.sukazyo.cono.morny.Log.logger +import cc.sukazyo.cono.morny.daemon.MornyReport +import cc.sukazyo.cono.morny.util.tgapi.InputCommand +import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramFormatter.* 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 { @@ -30,7 +30,7 @@ object MornyManagers { event.message.chat.id, TelegramStickers ID_EXIT ).replyToMessageId(event.message.messageId) - logger info s"Morny exited by user ${(TGToString as user) toStringLogTag}" + logger info s"Morny exited by user ${user toLogTag}" MornyCoeur.exit(0, user) } else { @@ -39,7 +39,7 @@ object MornyManagers { event.message.chat.id, TelegramStickers ID_403 ).replyToMessageId(event.message.messageId) - logger info s"403 exit caught from user ${(TGToString as user) toStringLogTag}" + logger info s"403 exit caught from user ${user toLogTag}" MornyReport.unauthenticatedAction("/exit", user) } @@ -61,7 +61,7 @@ object MornyManagers { if (MornyCoeur.trusted isTrusted user.id) { - logger info s"call save from command by ${(TGToString as user) toStringLogTag}" + logger info s"call save from command by ${user toLogTag}" MornyCoeur.callSaveData() MornyCoeur.extra exec SendSticker( event.message.chat.id, @@ -74,7 +74,7 @@ object MornyManagers { event.message.chat.id, TelegramStickers ID_403 ).replyToMessageId(event.message.messageId) - logger info s"403 save caught from user ${(TGToString as user) toStringLogTag}" + logger info s"403 save caught from user ${user toLogTag}" 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 index 23fa2fa..327d7df 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyOldJrrp.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyOldJrrp.scala @@ -1,9 +1,9 @@ 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 cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramFormatter.* +import cc.sukazyo.cono.morny.util.tgapi.InputCommand +import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.model.request.ParseMode import com.pengrad.telegrambot.request.SendMessage @@ -24,11 +24,11 @@ object MornyOldJrrp extends ITelegramCommand { case a if a > 30 => ";" case _ => "..." - import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h + import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramParseEscape.escapeHtml as h MornyCoeur.extra exec SendMessage( event.message.chat.id, // language=html - f"${(TGToString as user) fullnameRefHtml} 在(utc的)今天的运气指数是———— $jrrp%.2f%%${h(ending)}" + f"${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 80c0c46..4d7e343 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 @@ -2,8 +2,8 @@ package cc.sukazyo.cono.morny.bot.command import cc.sukazyo.cono.morny.MornyCoeur import cc.sukazyo.cono.morny.data.{NbnhhshQuery, TelegramStickers} +import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramParseEscape.escapeHtml as h import cc.sukazyo.cono.morny.util.tgapi.InputCommand -import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.model.request.ParseMode import com.pengrad.telegrambot.request.{SendMessage, SendSticker} @@ -25,11 +25,10 @@ object Nbnhhsh extends ITelegramCommand { override def execute (using command: InputCommand, event: Update): Unit = { val queryTarget: String|Null = - import cc.sukazyo.cono.morny.util.CommonConvert.stringsConnecting if (event.message.replyToMessage != null && event.message.replyToMessage.text != null) event.message.replyToMessage.text - else if command hasArgs then - stringsConnecting(command.getArgs, " ", 0, command.getArgs.length-1) + else if command.args nonEmpty then + command.args mkString " " else null if (queryTarget == null) 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 0e249d4..8696bb8 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/command/私わね.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/私わね.scala @@ -2,7 +2,8 @@ package cc.sukazyo.cono.morny.bot.command import cc.sukazyo.cono.morny.MornyCoeur import cc.sukazyo.cono.morny.util.tgapi.InputCommand -import cc.sukazyo.cono.morny.util.CommonRandom.probabilityTrue +import cc.sukazyo.cono.morny.util.UseMath.over +import cc.sukazyo.cono.morny.util.UseRandom.* import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.request.SendMessage @@ -13,7 +14,7 @@ object 私わね extends ISimpleCommand { override def execute (using command: InputCommand, event: Update): Unit = { - if (probabilityTrue(521)) { + if ((1 over 521) chance_is true) { val text = "/打假" MornyCoeur.extra exec new SendMessage( event.message.chat.id, 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 68ad75c..a8d16b3 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 @@ -3,9 +3,9 @@ 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.data.TelegramStickers -import cc.sukazyo.cono.morny.util.tgapi.formatting.TGToString -import com.pengrad.telegrambot.model.request.ParseMode +import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramFormatter.* import com.pengrad.telegrambot.model.{Chat, Message, Update, User} +import com.pengrad.telegrambot.model.request.ParseMode import com.pengrad.telegrambot.request.{ForwardMessage, GetChat, SendMessage, SendSticker} import scala.language.postfixOps @@ -44,7 +44,7 @@ object OnCallMe extends EventListener { MornyCoeur.extra exec SendMessage( me, s"""request $itemHTML - |from ${(TGToString as user) fullnameRefHtml}${if extra == null then "" else "\n"+extra}""" + |from ${user.fullnameRefHTML}${if extra == null then "" else "\n"+extra}""" .stripMargin ).parseMode(ParseMode HTML) @@ -59,7 +59,7 @@ object OnCallMe extends EventListener { lastDinnerData.forwardFromMessageId ) import cc.sukazyo.cono.morny.util.CommonFormat.{formatDate, formatDuration} - import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h + import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramParseEscape.escapeHtml as h def lastDinner_dateMillis: Long = lastDinnerData.forwardDate longValue; MornyCoeur.extra exec SendMessage( req.from.id, 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 index d4bb8ca..1065a29 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnCallMsgSend.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnCallMsgSend.scala @@ -3,7 +3,6 @@ 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} @@ -108,11 +107,11 @@ object OnCallMsgSend extends EventListener { val targetChatResponse = MornyCoeur.account 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 + import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramFormatter.* + import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramParseEscape.escapeHtml as h // 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}""" + |${chat.typeTag} ${h(chat.safe_name)} ${chat.safe_linkHTML}""" .stripMargin MornyCoeur.extra exec SendMessage( update.message.chat.id, 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 index d618ddc..121b3ef 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnEventHackHandle.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnEventHackHandle.scala @@ -1,8 +1,6 @@ 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 @@ -10,6 +8,7 @@ import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.model.request.ParseMode import com.pengrad.telegrambot.request.SendMessage +import scala.collection.mutable import scala.language.postfixOps object OnEventHackHandle extends EventListener { @@ -39,7 +38,7 @@ object OnEventHackHandle extends EventListener { 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 + import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramParseEscape.escapeHtml as h MornyCoeur.extra exec SendMessage( x.from_chat, // language=html 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 index 825f2d5..601cafc 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnQuestionMarkReply.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnQuestionMarkReply.scala @@ -15,8 +15,9 @@ object OnQuestionMarkReply extends EventListener { if event.message.text eq null then return false - import cc.sukazyo.cono.morny.util.CommonRandom.probabilityTrue - if !probabilityTrue(8) then return false + import cc.sukazyo.cono.morny.util.UseMath.over + import cc.sukazyo.cono.morny.util.UseRandom.chance_is + if (1 over 8) chance_is false then return false for (c <- event.message.text toCharArray) if !(QUESTION_MARKS contains c) then return false 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 index b82a66a..a2ef6ea 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnTelegramCommand.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnTelegramCommand.scala @@ -1,11 +1,11 @@ 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 +import cc.sukazyo.cono.morny.util.tgapi.InputCommand +import com.pengrad.telegrambot.model.{Message, Update} object OnTelegramCommand extends EventListener { @@ -19,10 +19,10 @@ object OnTelegramCommand extends EventListener { if !_isCommandMessage(update.message) then return false val inputCommand = InputCommand(update.message.text drop 1) - if (!(inputCommand.getCommand matches "^\\w+$")) + if (!(inputCommand.command matches "^\\w+$")) logger debug "not command" false - else if ((inputCommand.getTarget ne null) && (inputCommand.getTarget ne MornyCoeur.username)) + else if ((inputCommand.target ne null) && (inputCommand.target ne MornyCoeur.username)) logger debug "not morny command" false else 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 1657169..df18cb7 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 @@ -17,13 +17,13 @@ object OnUserRandom extends EventListener { if update.message.text == null then return false if update.message.text startsWith "/" then return false - import cc.sukazyo.cono.morny.util.CommonRandom.iif + import cc.sukazyo.cono.morny.util.UseRandom.rand_half val query = update.message.text substring 1 val result: String|Null = query match case USER_OR_QUERY(_con1, _con2) => - if iif then _con1 else _con2 + if rand_half then _con1 else _con2 case USER_IF_QUERY(_con) => - (if iif then "不" else "") + _con + (if rand_half then "不" else "") + _con case _ => null if result == null 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 9447a91..1778dfc 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 @@ -2,9 +2,9 @@ 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.TelegramFormatter.* +import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramParseEscape.escapeHtml as h import cc.sukazyo.cono.morny.util.UniversalCommand -import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h -import cc.sukazyo.cono.morny.util.tgapi.formatting.TGToString import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.model.request.ParseMode import com.pengrad.telegrambot.request.SendMessage @@ -22,7 +22,7 @@ object OnUserSlashAction extends EventListener { if (text startsWith "/") { - val actions = UniversalCommand format text + val actions = UniversalCommand(text) actions(0) = actions(0) substring 1 actions(0) @@ -51,11 +51,11 @@ object OnUserSlashAction extends EventListener { MornyCoeur.extra exec SendMessage( update.message.chat.id, "%s %s%s %s %s!".format( - (TGToString as origin) getSenderFirstNameRefHtml, + origin.sender_firstnameRefHTML, h(v_verb), if hasObject then "" else "了", if (origin == target) - s"自己" - else (TGToString as target) getSenderFirstNameRefHtml, + s"自己" + else origin.sender_firstnameRefHTML, if hasObject then h(v_object+" ") else "" ) ).parseMode(ParseMode HTML).replyToMessageId(update.message.messageId) 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 6275c2e..b6066e0 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,6 @@ package cc.sukazyo.cono.morny.bot.query -import cc.sukazyo.cono.morny.util.tgapi.formatting.NamedUtils.inlineIds +import cc.sukazyo.cono.morny.util.tgapi.formatting.NamingUtils.inlineQueryId import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramUserInformation import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.model.request.{InlineQueryResultArticle, InputTextMessageContent, ParseMode} @@ -18,9 +18,9 @@ object MyInformation extends ITelegramQuery { List( InlineQueryUnit(InlineQueryResultArticle( - inlineIds(ID_PREFIX), TITLE, + inlineQueryId(ID_PREFIX), TITLE, new InputTextMessageContent( - TelegramUserInformation informationOutputHTML event.inlineQuery.from + TelegramUserInformation getFormattedInformation event.inlineQuery.from ).parseMode(ParseMode HTML) )).isPersonal(true).cacheTime(10) ) 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 aec52f6..4fe13c8 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,5 @@ package cc.sukazyo.cono.morny.bot.query -import cc.sukazyo.cono.morny.util.tgapi.formatting.NamedUtils.inlineIds +import cc.sukazyo.cono.morny.util.tgapi.formatting.NamingUtils.inlineQueryId import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.model.request.{InlineQueryResultArticle, InputTextMessageContent} @@ -16,7 +16,7 @@ object RawText extends ITelegramQuery { List( InlineQueryUnit(InlineQueryResultArticle( - inlineIds(ID_PREFIX, event.inlineQuery.query), TITLE, + inlineQueryId(ID_PREFIX, event.inlineQuery.query), TITLE, InputTextMessageContent(event.inlineQuery.query) )) ) 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 bc1a4e7..7b2f750 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,8 +1,8 @@ package cc.sukazyo.cono.morny.bot.query import cc.sukazyo.cono.morny.Log.logger +import cc.sukazyo.cono.morny.util.tgapi.formatting.NamingUtils.inlineQueryId import cc.sukazyo.cono.morny.util.BiliTool -import cc.sukazyo.cono.morny.util.tgapi.formatting.NamedUtils.inlineIds import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.model.request.{InlineQueryResultArticle, InputTextMessageContent, ParseMode} @@ -60,11 +60,11 @@ object ShareToolBilibili extends ITelegramQuery { List( InlineQueryUnit(InlineQueryResultArticle( - inlineIds(ID_PREFIX_BILI_AV+av), TITLE_BILI_AV+av, + inlineQueryId(ID_PREFIX_BILI_AV+av), TITLE_BILI_AV+av, InputTextMessageContent(SHARE_FORMAT_HTML.format(link_av, id_av)).parseMode(ParseMode HTML) )), InlineQueryUnit(InlineQueryResultArticle( - inlineIds(ID_PREFIX_BILI_BV + bv), TITLE_BILI_BV + bv, + inlineQueryId(ID_PREFIX_BILI_BV + bv), TITLE_BILI_BV + bv, InputTextMessageContent(SHARE_FORMAT_HTML.format(link_bv, id_bv)).parseMode(ParseMode HTML) )) ) 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 ffc7f0e..572c32e 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,10 +1,9 @@ package cc.sukazyo.cono.morny.bot.query +import cc.sukazyo.cono.morny.util.tgapi.formatting.NamingUtils.inlineQueryId import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.model.request.InlineQueryResultArticle -import cc.sukazyo.cono.morny.util.tgapi.formatting.NamedUtils.inlineIds - import scala.language.postfixOps import scala.util.matching.Regex @@ -25,11 +24,11 @@ object ShareToolTwitter extends ITelegramQuery { case REGEX_TWEET_LINK(_1, _2, _) => List( InlineQueryUnit(InlineQueryResultArticle( - inlineIds(ID_PREFIX_VX+event.inlineQuery.query), TITLE_VX, + inlineQueryId(ID_PREFIX_VX+event.inlineQuery.query), TITLE_VX, s"https://vxtwitter.com/$_2" )), InlineQueryUnit(InlineQueryResultArticle( - inlineIds(ID_PREFIX_VX_COMBINED+event.inlineQuery.query), TITLE_VX_COMBINED, + inlineQueryId(ID_PREFIX_VX_COMBINED+event.inlineQuery.query), TITLE_VX_COMBINED, s"https://c.vxtwitter.com/$_2" )) ) diff --git a/src/main/scala/cc/sukazyo/cono/morny/daemon/MornyReport.scala b/src/main/scala/cc/sukazyo/cono/morny/daemon/MornyReport.scala index cba4ccf..9591fb1 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/daemon/MornyReport.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/daemon/MornyReport.scala @@ -1,16 +1,16 @@ package cc.sukazyo.cono.morny.daemon import cc.sukazyo.cono.morny.{MornyCoeur, MornyConfig} -import cc.sukazyo.cono.morny.util.tgapi.event.EventRuntimeException -import com.pengrad.telegrambot.request.{BaseRequest, SendMessage} -import com.pengrad.telegrambot.response.BaseResponse import cc.sukazyo.cono.morny.Log.{exceptionLog, logger} import cc.sukazyo.cono.morny.bot.command.MornyInformation +import cc.sukazyo.cono.morny.util.tgapi.event.EventRuntimeException +import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramFormatter.* +import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramParseEscape.escapeHtml as h import com.google.gson.GsonBuilder import com.pengrad.telegrambot.model.request.ParseMode import com.pengrad.telegrambot.model.User -import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h -import cc.sukazyo.cono.morny.util.tgapi.formatting.TGToString +import com.pengrad.telegrambot.request.{BaseRequest, SendMessage} +import com.pengrad.telegrambot.response.BaseResponse object MornyReport { @@ -25,7 +25,7 @@ object MornyReport { s"""cannot execute report to telegram: |${exceptionLog(e) indent 4} | tg-api response: - |${(e.getResponse toString) indent 4}""" + |${(e.response toString) indent 4}""" .stripMargin } } @@ -36,7 +36,7 @@ object MornyReport { case api: EventRuntimeException.ActionFailed => // language=html "\n\ntg-api error:\n
%s
" - .formatted(GsonBuilder().setPrettyPrinting().create.toJson(api.getResponse)) + .formatted(GsonBuilder().setPrettyPrinting().create.toJson(api.response)) case _ => "" executeReport(SendMessage( MornyCoeur.config.reportToChat, @@ -55,7 +55,7 @@ object MornyReport { // language=html s"""▌User unauthenticated action |action: ${h(action)} - |by user ${(TGToString as user) fullnameRefHtml}""" + |by user ${user.fullnameRefHTML}""" .stripMargin ).parseMode(ParseMode HTML)) } @@ -105,7 +105,7 @@ object MornyReport { def onMornyExit (causedBy: AnyRef|Null): Unit = { if unsupported then return val causedTag = causedBy match - case u: User => (TGToString as u) fullnameRefHtml + case u: User => u.fullnameRefHTML case n if n == null => "UNKNOWN reason" case a: AnyRef => /*language=html*/ s"${h(a.toString)}" executeReport(SendMessage( diff --git a/src/main/scala/cc/sukazyo/cono/morny/data/MornyJrrp.scala b/src/main/scala/cc/sukazyo/cono/morny/data/MornyJrrp.scala index 87f3364..d6ec709 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/data/MornyJrrp.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/data/MornyJrrp.scala @@ -10,8 +10,8 @@ object MornyJrrp { 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) + import cc.sukazyo.cono.morny.util.CommonEncrypt.MD5 + import cc.sukazyo.cono.morny.util.ConvertByteHex.toHex + (java.lang.Long parseLong MD5(s"$identifier@$dayStamp").toHex.substring(0, 4)) / (0xffff toDouble) } diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/BiliTool.scala b/src/main/scala/cc/sukazyo/cono/morny/util/BiliTool.scala new file mode 100644 index 0000000..37a2473 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/util/BiliTool.scala @@ -0,0 +1,119 @@ +package cc.sukazyo.cono.morny.util + +import cc.sukazyo.cono.morny.util.UseMath.** + +import scala.collection.mutable + +/** Utils about $Bilibili + * + * contains utils: + * - av/BV converting: + * - [[toAv]] + * - [[toBv]] + * + * @define Bilibili [[https://bilibili.com Bilibili]] + * + * @define AvBvFormat + * === About AV/BV id format === + * the AV id is a number; the BV id is a special 10 digits base58 number, it shows as String + * in programming. + * + * e.g. while the link ''`https://www.bilibili.com/video/BV17x411w7KC/`'' shows + * the same with ''`https://www.bilibili.com/video/av170001/`'', the AV id + * is __`170001`__, the BV id is __`BV17x411w7KC`__. + * + * @define AvBvSeeAlso [[https://www.zhihu.com/question/381784377/answer/1099438784 mcfx的回复: 如何看待 2020 年 3 月 23 日哔哩哔哩将稿件的「av 号」变更为「BV 号」?]] + * @todo Maybe make a class `AV`/`BV` and implement the parse in the class + */ +object BiliTool { + + private val V_CONV_XOR = 177451812L + private val V_CONV_ADD = 8728348608L + + private val BV_TABLE = "fZodR9XQDSUm21yCkr6zBqiveYah8bt4xsWpHnJE7jL5VG3guMTKNPAwcF" + private val TABLE_INT = BV_TABLE.length + private val BV_TABLE_REVERSED = + val mapping = mutable.HashMap.empty[Char, Int] + for (i <- BV_TABLE.indices) mapping += (BV_TABLE(i) -> i) + mapping.toMap + private val BV_TEMPLATE = "1 4 1 7 " + private val BV_TEMPLATE_FILTER = Array(9, 8, 1, 6, 2, 4) + + /** Error of illegal BV id. + * + * @constructor Build a error with illegal BV details. + * @param bv the source illegal BV id. + * @param reason why it is illegal. + */ + class IllegalFormatException private (bv: String, reason: String) + extends RuntimeException (s"`$bv is not a valid 10 digits base58 BV id: $reason`") { + + /** Error of illegal BV id, where the reason is the BV id is not 10 digits. + * + * @param bv the source of illegal BV id. + * @param length the length of the illegal BV id. + */ + def this (bv: String, length: Int) = + this(bv, s"given length is $length") + + /** Error of illegal BV id, where the reason is the BV id contains non [[BV_TABLE base58 character]]. + * + * @param bv the source of illegal BV id. + * @param c the illegal character + * @param location the index of the illegal character in the illegal BV id. + */ + def this (bv: String, c: Char, location: Int) = + this(bv, s"char `$c` is not in base58 char table (in position $location)") + } + + /** Convert an AV video id format to BV video id format for $Bilibili + * + * $AvBvFormat + * + * this method '''available while the __av-id < 2^27^__''', while it theoretically + * available when the av-id < 2^30^. Meanwhile some digits of the BV id is a fixed + * value (like the [[BV_TEMPLATE]] shows) -- input __bv__ can do not follow the format, + * but it will almost certainly gives a wrong AV id (because the fixed number is not + * processed at all!) + * + * @see $AvBvSeeAlso + * + * @param bv a BV id, which should be exactly 10 digits and all chars should be + * a legal base58 char (which means can be found in [[BV_TABLE]]). + * otherwise, an [[IllegalFormatException]] will be thrown. + * @return an AV id which will shows the save video of input __bv__ in $Bilibili + * @throws IllegalFormatException when the input __bv__ is not a legal 10 digits base58 + * formatted BV id. + */ + @throws[IllegalFormatException] + def toAv (bv: String): Long = { + var av = 0L + if (bv.length != 10) throw IllegalFormatException(bv, bv.length) + for (i <- BV_TEMPLATE_FILTER.indices) { + val _get = BV_TEMPLATE_FILTER(i) + val tableToken = BV_TABLE_REVERSED get bv(_get) + if tableToken isEmpty then throw IllegalFormatException(bv, bv(_get), _get) + av = av + (tableToken.get * (TABLE_INT**i).toLong) + } + (av - V_CONV_ADD) ^ V_CONV_XOR + } + + /** Convert an AV video format to a BV video format for $Bilibili. + * + * this method '''available while the __av-id < 2^27^__''', while it theoretically + * available when the av-id < 2^30^. + * + * @param av an AV id. + * @return a BV id which will shows the save video of input __av__ in $Bilibili + */ + def toBv (av: Long): String = { + val _av = (av^V_CONV_XOR)+V_CONV_ADD + val bv = Array(BV_TEMPLATE:_*) + for (i <- BV_TEMPLATE_FILTER.indices) { + import Math.{floor, pow} + bv(BV_TEMPLATE_FILTER(i)) = BV_TABLE( (floor(_av/(TABLE_INT**i)) % TABLE_INT) toInt ) + } + String copyValueOf bv + } + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/CommonEncrypt.scala b/src/main/scala/cc/sukazyo/cono/morny/util/CommonEncrypt.scala new file mode 100644 index 0000000..740e048 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/util/CommonEncrypt.scala @@ -0,0 +1,98 @@ +package cc.sukazyo.cono.morny.util + +import java.nio.charset.{Charset, StandardCharsets} +import java.security.{MessageDigest, NoSuchAlgorithmException} + +/** Provides some re-encapsulated algorithm function, and some standard values in encrypting, + * and some normalized utils in processing something in encrypting. + * + * currently there's: + * - standard value: + * - [[ENCRYPT_STANDARD_CHARSET]] the standard [[Charset]] to parse between [[String]] + * and [[Bin]] in encrypting. + * - algorithm encapsulations: + * - [[MD5]] (MD5 Message-Digest Algorithm) + * - [[SHA1]] (Secure Hash Algorithm 1) + * - [[SHA256]] (Secure Hash Algorithm 2: 256bit) + * - [[SHA512]] (Secure Hash Algorithm 2: 512bit) + * - normalized utils + * - [[lint_base64FileName]] remove the .base64 file-extension for base64 text file + * + * @define WhenString2Bin + * [[String]] will encoded to [[Bin]] using [[Charset]] [[ENCRYPT_STANDARD_CHARSET]] + * + * @todo some tests + */ +object CommonEncrypt { + + /** the [[Charset]] should use when converting between [[String]] + * and [[Bin]] in encrypting */ + val ENCRYPT_STANDARD_CHARSET: Charset = StandardCharsets.UTF_8 + + /** the alias of [[Array]]`[`[[Byte]]`]`. + * means the binary data. + */ + //noinspection ScalaWeakerAccess + type Bin = Array[Byte] + + private def hash (data: Bin)(using algorithm: String): Bin = + try { + MessageDigest.getInstance(algorithm) digest data + } catch case n: NoSuchAlgorithmException => + throw IllegalStateException(n) + + /** the [[https://en.wikipedia.org/wiki/MD5 MD5]] hash value of input [[Bin]] `data`. */ + def MD5(data: Bin): Bin = hash(data)(using "md5") + /** the [[https://en.wikipedia.org/wiki/MD5 MD5]] hash value of input [[String]] `data`. + * + * $WhenString2Bin + */ + def MD5 (data: String): Bin = hash(data getBytes ENCRYPT_STANDARD_CHARSET)(using "md5") + + /** the [[https://en.wikipedia.org/wiki/SHA-1 SHA-1]] hash value of input [[Bin]] `data`. */ + def SHA1 (data: Bin): Bin = hash(data)(using "sha1") + /** the [[https://en.wikipedia.org/wiki/SHA-1 SHA-1]] hash value of input [[String]] `data`. + * + * $WhenString2Bin + */ + def SHA1 (data: String): Bin = hash(data getBytes ENCRYPT_STANDARD_CHARSET)(using "sha1") + + /** the [[https://en.wikipedia.org/wiki/SHA-2 SHA-2/256]] hash value of input [[Bin]] `data`. */ + def SHA256 (data: Bin): Bin = hash(data)(using "sha256") + /** the [[https://en.wikipedia.org/wiki/SHA-2 SHA-2/256]] hash value of input [[String]] `data`. + * + * $WhenString2Bin + */ + def SHA256 (data: String): Bin = hash(data getBytes ENCRYPT_STANDARD_CHARSET)(using "sha256") + + /** the [[https://en.wikipedia.org/wiki/SHA-2 SHA-2/512]] hash value of input [[Bin]] `data`. */ + def SHA512 (data: Bin): Bin = hash(data)(using "sha512") + /** the [[https://en.wikipedia.org/wiki/SHA-2 SHA-2/512]] hash value of input [[String]] `data`. + * + * $WhenString2Bin + */ + def SHA512 (data: String): Bin = hash(data getBytes ENCRYPT_STANDARD_CHARSET)(using "sha512") + + /** Try get the filename before it got encrypted. + * + * It assumes the base64 encrypted file should keep the original file, and plus + * a file-extension shows the file is base64 encrypted. + * + * Actually, the file will try find the following file-extension and drop it: + * - `.b64` + * - `.64.txt` + * - `.base64` + * - `.base64.txt` + * if none of those found, it will do no process anymore. + * + * @param encrypted the file fullname (means filename with file-extension) of base64 encrypted file. + * @return the file fullname removed the base64 file extension. + */ + def lint_base64FileName (encrypted: String): String = encrypted match + case i if i endsWith ".b64" => i dropRight ".b64".length + case ix if ix endsWith ".b64.txt" => ix dropRight ".b64.txt".length + case l if l endsWith ".base64" => l dropRight ".base64".length + case lx if lx endsWith ".base64.txt" => lx dropRight ".base64.txt".length + case u => u + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/CommonFormat.scala b/src/main/scala/cc/sukazyo/cono/morny/util/CommonFormat.scala new file mode 100644 index 0000000..0ab5d36 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/util/CommonFormat.scala @@ -0,0 +1,76 @@ +package cc.sukazyo.cono.morny.util + +import java.time.{Instant, LocalDateTime, ZoneId, ZoneOffset} +import java.time.format.DateTimeFormatter + +/** Some formatting (convert some data to some standard output type) + * methods normalized based on Morny's usage + * + * contains: + * - [[DATE_TIME_PATTERN_FULL_MILLIS]] the standard date-time-millis [[String]] pattern format + * - [[formatDate]] convert UTC time millis (and hour-offset time zone) + * to normalized date-time-millis [[String]] + * - [[formatDuration]] convert millis duration to normalized duration [[String]] + * + */ +object CommonFormat { + + /** the standard date-time-millis [[String]] pattern format that Morny in use. + * + * pattern string is pattern of [[DateTimeFormatter]]. + */ + //noinspection ScalaWeakerAccess + val DATE_TIME_PATTERN_FULL_MILLIS = "yyyy-MM-dd HH:mm:ss:SSS" + + /** the formatted date-time-millis [[String]]. + * + * time is formatted by pattern [[DATE_TIME_PATTERN_FULL_MILLIS]]. + * + * @param timestamp millis timestamp. timestamp should be UTC alignment. + * + * @param utcOffset the hour offset of the time zone, the time-zone controls + * which local time describe will use. + * + * for example, timestamp [[0]] describes 1970-1-1 00:00:00 in + * UTC+0, so, use the `timestamp` `0` and `utfOffset` `0` will + * returns `"1970-1-1 00:00:00:000"`; however, at the same time, + * in UTC+8, the local time is 1970-1-1 08:00:00:000, so use + * the `timestamp` `0` and the `utcOffset` `8` will returns + * `"1970-1-1 08:00:00:000"` + * + * @return the time-zone local date-time-millis [[String]] describes the timestamp. + */ + def formatDate (timestamp: Long, utcOffset: Int): String = + DateTimeFormatter.ofPattern(DATE_TIME_PATTERN_FULL_MILLIS).format( + LocalDateTime.ofInstant( + Instant.ofEpochMilli(timestamp), + ZoneId.ofOffset("UTC", ZoneOffset.ofHours(utcOffset)) + ) + ) + + /** human readable [[String]] that describes the millis duration. + * + * {{{ + * scala> formatDuration(10) + * val res0: String = 10ms + * + * scala> formatDuration(3000001) + * val res1: String = 50min 0s 1ms + * + * scala> formatDuration(94179047901720L) + * val res2: String = 1090035d 6h 38min 21s 720ms + * }}} + * + * @param duration time duration, in milliseconds + * @return time duration, human readable + */ + def formatDuration (duration: Long): String = + val sb = new StringBuilder() + if (duration > 1000 * 60 * 60 * 24) sb ++= (duration / (1000 * 60 * 60 * 24)).toString ++= "d " + if (duration > 1000 * 60 * 60) sb ++= (duration / (1000 * 60 * 60) % 24).toString ++= "h " + if (duration > 1000 * 60) sb ++= (duration / (1000 * 60) % 60).toString ++= "min " + if (duration > 1000) sb ++= (duration / 1000 % 60).toString ++= "s " + sb ++= (duration % 1000).toString ++= "ms" + sb toString + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/ConvertByteHex.scala b/src/main/scala/cc/sukazyo/cono/morny/util/ConvertByteHex.scala new file mode 100644 index 0000000..0d469d4 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/util/ConvertByteHex.scala @@ -0,0 +1,55 @@ +package cc.sukazyo.cono.morny.util + +/** Added the [[toHex]] method to [[Byte]] and [[Array]]`[`[[Byte]]`]`. + * + * the [[toHex]] method will takes [[Byte]] as a binary byte and convert + * it to the hex [[String]] that can describe the binary byte. there are + * always 2 digits unsigned hex number. + * + * for example, byte `0` is binary `0000 0000`, it will be converted to + * `"00"`, and the byte `-1` is binary `1111 1111` which corresponding + * `"ff"`. + * {{{ + * scala> 0.toByte.toHex + * val res6: String = 00 + * + * scala> 15.toByte.toHex + * val res10: String = 0f + * + * scala> -1.toByte.toHex + * val res7: String = ff + * }}} + * + * while converting byte array, the order is: the 1st element of the array + * will be put most forward, then the following added to the tail of hex string. + * {{{ + * scala> Array[Byte](0, 1, 2, 3).toHex + * val res5: String = 00010203 + * }}} + * + */ +object ConvertByteHex { + + extension (b: Byte) { + + /** convert the binary of the [[Byte]] contains to hex string. + * @see [[ConvertByteHex]] + */ + def toHex: String = (b >> 4 & 0xf).toHexString + (b & 0xf).toHexString + + } + + extension (data: Array[Byte]) { + + /** convert the binary of the [[Array]]`[`[[Byte]]`]` contains to hex string. + * + * @see [[ConvertByteHex]] + */ + def toHex: String = + val sb = StringBuilder() + for (b <- data) sb ++= (b toHex) + sb toString + + } + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/FileUtils.scala b/src/main/scala/cc/sukazyo/cono/morny/util/FileUtils.scala new file mode 100644 index 0000000..f1e146b --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/util/FileUtils.scala @@ -0,0 +1,28 @@ +package cc.sukazyo.cono.morny.util + +import java.io.{FileInputStream, IOException} +import java.security.{MessageDigest, NoSuchAlgorithmException} +import scala.util.Using + +/** + * @todo docs + * @todo some tests? + */ +object FileUtils { + + @throws[IOException|NoSuchAlgorithmException] + def getMD5Three (path: String): String = { + val buffer = Array.ofDim[Byte](8192) + var len = 0 + val algo = MessageDigest.getInstance("MD5") + Using (FileInputStream(path)) { stream => + len = stream.read(buffer) + while (len != -1) + algo update (buffer, 0, len) + len = stream.read(buffer) + } + import ConvertByteHex.toHex + algo.digest toHex + } + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/OkHttpPublic.scala b/src/main/scala/cc/sukazyo/cono/morny/util/OkHttpPublic.scala new file mode 100644 index 0000000..fd7d19e --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/util/OkHttpPublic.scala @@ -0,0 +1,13 @@ +package cc.sukazyo.cono.morny.util + +import okhttp3.MediaType + +/** some public values of [[okhttp3]] */ +object OkHttpPublic { + + /** predefined [[okhttp3]] [[MediaType]]s */ + object MediaTypes: + /** [[MediaType]] of [[https://en.wikipedia.org/wiki/JSON JSON]]. using encoding ''UTF-8'' */ + val JSON: MediaType = MediaType.get("application/json; charset=utf-8") + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/UniversalCommand.scala b/src/main/scala/cc/sukazyo/cono/morny/util/UniversalCommand.scala new file mode 100644 index 0000000..65a1e87 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/util/UniversalCommand.scala @@ -0,0 +1,75 @@ +package cc.sukazyo.cono.morny.util + +import scala.collection.mutable.ArrayBuffer +import scala.util.boundary + +/** + * @todo docs + * @todo maybe there can have some encapsulation + */ +object UniversalCommand { + + def apply (input: String): Array[String] = { + + val builder = ArrayBuffer.empty[String] + + extension (c: Char) { + private inline def isUnsupported: Boolean = + (c == '\n') || (c == '\r') + private inline def isSeparator: Boolean = + c == ' ' + private inline def isQuote: Boolean = + (c == '\'') || (c == '"') + private inline def isEscapeChar: Boolean = + c == '\\' + private inline def escapableInQuote: Boolean = + c.isQuote || c.isEscapeChar + private inline def escapable: Boolean = + c.escapableInQuote || c.isSeparator + } + + var arg = StringBuilder() + var i = 0 + while (i < input.length) { + if (input(i) isSeparator) { + if (arg nonEmpty) builder += arg.toString + arg = arg.empty + } else if (input(i) isQuote) { + val _inside_tag = input(i) + var _inside = true + boundary { while (_inside) { + i=i+1 + if (i >= input.length) throw IllegalArgumentException("UniversalCommand: unclosed quoted text") + if (input(i) == _inside_tag) + boundary.break() + else if (input(i) isUnsupported) + throw IllegalArgumentException("UniversalCommand: unsupported new-line") + else if (input(i) isQuote) + throw IllegalArgumentException("UniversalCommand: mixed \" and ' used") + else if (input(i) isEscapeChar) + if (i+1 >= input.length) throw IllegalArgumentException("UniversalCommand: \\ in the end") + if (input(i+1) escapableInQuote) + i=i+1 + arg += input(i) + else + arg += input(i) + }} + } else if (input(i) isUnsupported) { + throw IllegalArgumentException("UniversalCommand: unsupported new-line") + } else if (input(i) isEscapeChar) { + if (i + 1 >= input.length) throw IllegalArgumentException("UniversalCommand: \\ in the end") + if (input(i+1) escapable) + i=i+1 + arg += input(i) + } else { + arg += input(i) + } + i = i + 1 + } + if (arg nonEmpty) builder += arg.toString + + builder toArray + + } + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/UseMath.scala b/src/main/scala/cc/sukazyo/cono/morny/util/UseMath.scala new file mode 100644 index 0000000..5f11c38 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/util/UseMath.scala @@ -0,0 +1,19 @@ +package cc.sukazyo.cono.morny.util + +import scala.annotation.targetName + +/** @todo some tests */ +object UseMath { + + extension (self: Int) { + + def over (other: Int): Double = self.toDouble / other + + } + + extension (self: Int) { + @targetName("pow") + def ** (other: Int): Double = Math.pow(self, other) + } + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/UseRandom.scala b/src/main/scala/cc/sukazyo/cono/morny/util/UseRandom.scala new file mode 100644 index 0000000..b6eb096 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/util/UseRandom.scala @@ -0,0 +1,33 @@ +package cc.sukazyo.cono.morny.util + +import scala.language.implicitConversions +import scala.util.Random + +/** + * @todo some tests maybe? + * @todo use the using clauses to provide random instance + */ +object UseRandom { + + class ChancePossibility[T <: Any] (val one: T) (using possibility: Double) { + def nor[U] (another: U): T|U = + if Random.nextDouble < possibility then one else another + } + + given Conversion[ChancePossibility[Boolean], Boolean] with + def apply(in: ChancePossibility[Boolean]): Boolean = in nor !in.one + + extension (num: Double) { + + def chance_is[T <: Any] (one: T): ChancePossibility[T] = + ChancePossibility(one)(using num) + + } + + def rand_half: Boolean = Random.nextBoolean + + def rand_id: String = + import ConvertByteHex.toHex + Random nextBytes 6 toHex + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/package.scala b/src/main/scala/cc/sukazyo/cono/morny/util/package.scala new file mode 100644 index 0000000..43bf99c --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/util/package.scala @@ -0,0 +1,22 @@ +package cc.sukazyo.cono.morny + +/** Utils that [[cc.sukazyo.cono.morny]]'s code used. + * + * contains: + * - [[tgapi Telegram API/Utils Extras]] + * - extensions of language standard + * - [[CommonEncrypt]] re-encapsulated some encrypt algorithms, and some normalized while encrypting. + * - [[CommonFormat]] provides some format methods normalized based on Morny usage standard. + * - [[ConvertByteHex]] extensions [[Byte]] and so on, make it easier converting binary data in it to a hex string. + * - [[UseMath]] scala style to make Math function easier to use + * - [[UseRandom]] scala style to use Random to generate something + * - external library extras + * - [[OkHttpPublic]] defines some static value for [[okhttp3]] + * - useful misc utils + * - [[FileUtils]] contains some easy-to-use file action. + * - [[UniversalCommand]] provides a easy way to get an args array from a string input. + * - others + * - [[BiliTool about Bilibili]] + * + */ +package object util {} diff --git a/src/main/java/cc/sukazyo/cono/morny/util/tgapi/ExtraAction.java b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/ExtraAction.java similarity index 100% rename from src/main/java/cc/sukazyo/cono/morny/util/tgapi/ExtraAction.java rename to src/main/scala/cc/sukazyo/cono/morny/util/tgapi/ExtraAction.java diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/InputCommand.scala b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/InputCommand.scala new file mode 100644 index 0000000..f6c7e26 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/InputCommand.scala @@ -0,0 +1,31 @@ +package cc.sukazyo.cono.morny.util.tgapi + +import cc.sukazyo.cono.morny.util.UniversalCommand + +class InputCommand private ( + val target: String|Null, + val command: String, + val args: Array[String] +) { + + override def toString: String = + s"{{$command}@{$target}#{${args.mkString}}" + +} + +object InputCommand { + + def apply (input: Array[String]): InputCommand = { + val _ex = input(0) split ("@", 2) + val _args = input drop 1 + new InputCommand( + if _ex.length == 1 then null else _ex(1), + _ex(0), + _args + ) + } + + def apply (input: String): InputCommand = + InputCommand(UniversalCommand(input)) + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/Standardize.scala b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/Standardize.scala new file mode 100644 index 0000000..2796c02 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/Standardize.scala @@ -0,0 +1,9 @@ +package cc.sukazyo.cono.morny.util.tgapi + +object Standardize { + + val CHANNEL_SPEAKER_MAGIC_ID = 136817688 + + val MASK_BOTAPI_ID: Long = -1000000000000 + +} \ No newline at end of file diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/event/EventRuntimeException.scala b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/event/EventRuntimeException.scala new file mode 100644 index 0000000..b44e7be --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/event/EventRuntimeException.scala @@ -0,0 +1,9 @@ +package cc.sukazyo.cono.morny.util.tgapi.event + +import com.pengrad.telegrambot.response.BaseResponse + +class EventRuntimeException (message: String) extends RuntimeException(message) + +object EventRuntimeException { + class ActionFailed (message: String, val response: BaseResponse) extends EventRuntimeException(message) +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/NamingUtils.scala b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/NamingUtils.scala new file mode 100644 index 0000000..c0bc94b --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/NamingUtils.scala @@ -0,0 +1,11 @@ +package cc.sukazyo.cono.morny.util.tgapi.formatting + +import cc.sukazyo.cono.morny.util.CommonEncrypt +import cc.sukazyo.cono.morny.util.ConvertByteHex.toHex + +object NamingUtils { + + def inlineQueryId (tag: String, taggedData: String = ""): String = + CommonEncrypt.MD5(tag+taggedData) toHex + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramFormatter.scala b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramFormatter.scala new file mode 100644 index 0000000..acc0d49 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramFormatter.scala @@ -0,0 +1,82 @@ +package cc.sukazyo.cono.morny.util.tgapi.formatting + +import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramParseEscape.escapeHtml as h +import cc.sukazyo.cono.morny.util.tgapi.Standardize.MASK_BOTAPI_ID +import com.pengrad.telegrambot.model.{Chat, Message, User} +import com.pengrad.telegrambot.model.Chat.Type + +object TelegramFormatter { + + extension (chat: Chat) { + + def safe_name: String = chat.`type` match + case Type.Private => _connectName(chat.firstName, chat.lastName) + case _ => chat.title + + def safe_linkHTML: String = + if (chat.username == null) + chat.`type` match + // language=html + case Type.Private => s"@[u:${chat.id}]" + // language=html + case _ => s"@[c/${chat.id}]" + else s"@${h(chat.username)}" + + def safe_firstnameRefHTML: String = + chat.`type` match + // language=html + case Type.Private => s"${h(chat.firstName)}" + // language=html + case _ => s"${h(chat.title)}" + + def id_tdLib: Long = + if chat.id < 0 then (chat.id - MASK_BOTAPI_ID)abs else chat.id + + def typeTag: String = chat.`type` match + case Type.Private => "🔒" + case Type.group => "💭" + case Type.supergroup => "💬" + case Type.channel => "📢" + + } + + extension (user: User) { + + def fullname: String = _connectName(user.firstName, user.lastName) + + def fullnameRefHTML: String = + // language=html + s"${h(user.fullname)}" + + def firstnameRefHTML: String = + // language=html + s"${h(user.firstName)}" + + def toLogTag: String = + (if (user.username == null) user.fullname + " " else "@" + user.username) + + "[" + user.id + "]" + + } + + extension (m: Message) { + + def sender_id: Long = + if m.senderChat == null then m.from.id else m.senderChat.id + + def sender_firstnameRefHTML: String = + if (m.senderChat == null) + m.from.firstnameRefHTML + else m.senderChat.safe_firstnameRefHTML + + } + + private inline def _link_user (id: Long): String = + s"tg://user?id=$id" + + private inline def _link_chat (id: Long): String = + s"https://t.me/c/$id" + + private inline def _connectName (firstName: String, lastName: String): String = + firstName + (if lastName == null then "" else " " + lastName) + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramParseEscape.scala b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramParseEscape.scala new file mode 100644 index 0000000..4b27795 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramParseEscape.scala @@ -0,0 +1,12 @@ +package cc.sukazyo.cono.morny.util.tgapi.formatting + +object TelegramParseEscape { + + def escapeHtml (input: String): String = + var process = input + process = process.replaceAll("&", "&") + process = process.replaceAll("<", "<") + process = process.replaceAll(">", ">") + process + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramUserInformation.scala b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramUserInformation.scala new file mode 100644 index 0000000..81d87ee --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramUserInformation.scala @@ -0,0 +1,67 @@ +package cc.sukazyo.cono.morny.util.tgapi.formatting + +import com.pengrad.telegrambot.model.User +import okhttp3.{OkHttpClient, Request} + +import java.io.IOException +import scala.util.matching.Regex +import scala.util.Using + +object TelegramUserInformation { + + val DC_QUERY_SOURCE_SITE = "https://t.me/" + val DC_QUERY_PROCESSOR_REGEX: Regex = "(cdn[1-9]).tele(sco.pe|gram-cdn.org)"r + + private val httpClient = OkHttpClient() + + @throws[IllegalArgumentException|IOException] + def getDataCenterFromUser (username: String): String = { + val request = Request.Builder().url(DC_QUERY_SOURCE_SITE + username).build + Using (httpClient.newCall(request) execute) { response => + val body = response.body + if body eq null then "" + else DC_QUERY_PROCESSOR_REGEX.findFirstMatchIn(body.string) match + case Some(res) => res.group(1) + case None => "" + } get + } + + def getFormattedInformation (user: User): String = { + import TelegramParseEscape.escapeHtml as h + + val userInfo = StringBuilder() + + userInfo ++= // language=html + s"""userid : + |- ${user.id}""" + .stripMargin + userInfo ++= { + if (user.username eq null) // language=html + s""" + |username : null + |datacenter : not supported""" + .stripMargin + else // language=html + s""" + |username : + |- ${h(user.username)} + |datacenter : + |- ${h(getDataCenterFromUser(user.username))}""" + .stripMargin + } + userInfo ++= // language=html + s""" + |display name : + |- ${h(user.firstName)}${if user.lastName ne null then s"\n- ${h(user.lastName)}" else ""}""" + .stripMargin + if (user.languageCode ne null) userInfo ++= // language=html + s""" + |language-code : + |- ${user.languageCode}""" + .stripMargin + + userInfo toString + + } + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/package.scala b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/package.scala new file mode 100644 index 0000000..d646076 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/package.scala @@ -0,0 +1,4 @@ +package cc.sukazyo.cono.morny.util + +/** @todo docs */ +package object tgapi {} diff --git a/src/test/java/cc/sukazyo/cono/morny/MornyCLI.java b/src/test/java/cc/sukazyo/cono/morny/MornyCLI.java deleted file mode 100644 index 4a36d44..0000000 --- a/src/test/java/cc/sukazyo/cono/morny/MornyCLI.java +++ /dev/null @@ -1,18 +0,0 @@ -package cc.sukazyo.cono.morny; - -import cc.sukazyo.cono.morny.util.UniversalCommand; - -import java.util.*; - -public class MornyCLI { - - public static void main (String[] args) { - - System.out.print("$ java -jar morny-coeur-"+MornySystem.VERSION_FULL()+".jar " ); - String x; - try (Scanner line = new Scanner(System.in)) { x = line.nextLine(); } - ServerMain.main(UniversalCommand.format(x)); - - } - -} diff --git a/src/test/java/cc/sukazyo/cono/morny/daemon/TestMedicationTimer.java b/src/test/java/cc/sukazyo/cono/morny/daemon/TestMedicationTimer.java deleted file mode 100644 index d686ea0..0000000 --- a/src/test/java/cc/sukazyo/cono/morny/daemon/TestMedicationTimer.java +++ /dev/null @@ -1,36 +0,0 @@ -package cc.sukazyo.cono.morny.daemon; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; - -import java.time.ZoneOffset; -import java.time.ZonedDateTime; -import java.util.Set; - -import static cc.sukazyo.cono.morny.internal.ScalaJavaConv.jSetInteger2simm; - -public class TestMedicationTimer { - - @ParameterizedTest - @CsvSource(textBlock = """ - 2022-11-13T13:14:35.000+08, +08, 2022-11-13T19:00:00+08 - 2022-11-13T13:14:35.174+02, +02, 2022-11-13T19:00:00+02 - 1998-02-01T08:14:35.871+08, +08, 1998-02-01T19:00:00+08 - 2022-11-13T00:00:00.000-01, -01, 2022-11-13T07:00:00-01 - 2022-11-21T19:00:00.000+00, +00, 2022-11-21T21:00:00+00 - 2022-12-31T21:00:00.000+00, +00, 2023-01-01T07:00:00+00 - 2125-11-18T23:45:27.062+00, +00, 2125-11-19T07:00:00+00 - """) - void testCalcNextRoutineTimestamp (ZonedDateTime base, ZoneOffset zoneHour, ZonedDateTime expected) - throws IllegalArgumentException { - final Set at = Set.of(7, 19, 21); - System.out.println("base.toInstant().toEpochMilli() = " + base.toInstant().toEpochMilli()); - Assertions.assertEquals( - expected.toInstant().toEpochMilli(), - MedicationTimer.calcNextRoutineTimestamp(base.toInstant().toEpochMilli(), zoneHour, jSetInteger2simm(at)) - ); - System.out.println(" ok"); - } - -} diff --git a/src/test/java/cc/sukazyo/cono/morny/util/TestBiliTool.java b/src/test/java/cc/sukazyo/cono/morny/util/TestBiliTool.java deleted file mode 100644 index 125d9c6..0000000 --- a/src/test/java/cc/sukazyo/cono/morny/util/TestBiliTool.java +++ /dev/null @@ -1,30 +0,0 @@ -package cc.sukazyo.cono.morny.util; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; - -import static cc.sukazyo.cono.morny.util.BiliTool.*; - -public class TestBiliTool { - - private static final String AV_BV_DATA_CSV = """ - 17x411w7KC, 170001 - 1Q541167Qg, 455017605 - 1mK4y1C7Bz, 882584971 - 1T24y197V2, 688730800 - """; - - @ParameterizedTest - @CsvSource(textBlock = AV_BV_DATA_CSV) - void testAvToBv (String bv, int av) { - Assertions.assertEquals(bv, toBv(av)); - } - - @ParameterizedTest - @CsvSource(textBlock = AV_BV_DATA_CSV) - void testBvToAv (String bv, int av) { - Assertions.assertEquals(av, toAv(bv)); - } - -} diff --git a/src/test/java/cc/sukazyo/cono/morny/util/TestCommonConvert.java b/src/test/java/cc/sukazyo/cono/morny/util/TestCommonConvert.java deleted file mode 100644 index d35e55f..0000000 --- a/src/test/java/cc/sukazyo/cono/morny/util/TestCommonConvert.java +++ /dev/null @@ -1,47 +0,0 @@ -package cc.sukazyo.cono.morny.util; - -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; -import org.junit.jupiter.params.provider.EnumSource; - -import static cc.sukazyo.cono.morny.util.CommonConvert.byteArrayToHex; -import static cc.sukazyo.cono.morny.util.CommonConvert.byteToHex; -import static org.junit.jupiter.api.Assertions.assertEquals; - -public class TestCommonConvert { - - @ParameterizedTest - @CsvSource(textBlock = """ - 0x00, 00 - 0x01, 01 - 0x20, 20 - 0x77, 77 - -0x60, a0 - 0x0a, 0a - -0x01, ff - -0x05, fb - """ - ) - void testByteToHex(byte source, String expected) { - assertEquals(expected, byteToHex(source)); - } - - public enum TestByteArrayToHexSource { - $1(new T(new byte[]{0x00}, "00")), - $2(new T(new byte[]{(byte)0xff}, "ff")), - $3(new T(new byte[]{(byte)0xc3}, "c3")), - $4(new T(new byte[]{}, "")), - $5(new T(new byte[]{0x30,0x0a,0x00,0x04,(byte)0xb0,0x00}, "300a0004b000")), - $6(new T(new byte[]{0x00,0x00,0x0a,(byte)0xff,(byte)0xfc,(byte)0xab,(byte)0x00,0x04}, "00000afffcab0004")), - $7(new T(new byte[]{0x00,0x7c,0x11,0x28,(byte)0x88,(byte)0xa6,(byte)0xfc,0x30}, "007c112888a6fc30")); - public record T (byte[] raw, String expected) {} - public final T value; - TestByteArrayToHexSource (T value) { this.value = value; } - } - @ParameterizedTest - @EnumSource - void testByteArrayToHex (TestByteArrayToHexSource source) { - assertEquals(source.value.expected, byteArrayToHex(source.value.raw)); - } - -} diff --git a/src/test/java/cc/sukazyo/cono/morny/util/TestCommonEncrypt.java b/src/test/java/cc/sukazyo/cono/morny/util/TestCommonEncrypt.java deleted file mode 100644 index 429b163..0000000 --- a/src/test/java/cc/sukazyo/cono/morny/util/TestCommonEncrypt.java +++ /dev/null @@ -1,23 +0,0 @@ -package cc.sukazyo.cono.morny.util; - -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; - -import static cc.sukazyo.cono.morny.util.CommonConvert.byteArrayToHex; -import static cc.sukazyo.cono.morny.util.CommonEncrypt.*; -import static org.junit.jupiter.api.Assertions.assertEquals; - -public class TestCommonEncrypt { - - @ParameterizedTest - @SuppressWarnings("UnnecessaryStringEscape") - @CsvSource(textBlock = """ - 28be57d368b75051da76c068a6733284, '莲子' - 9644c5cbae223013228cd528817ba4f5, '莲子\n' - d41d8cd98f00b204e9800998ecf8427e, '' - """) - void testHashMd5_String (String md5, String text) { - assertEquals(md5, byteArrayToHex(hashMd5(text))); - } - -} diff --git a/src/test/java/cc/sukazyo/cono/morny/util/TestCommonFormat.java b/src/test/java/cc/sukazyo/cono/morny/util/TestCommonFormat.java deleted file mode 100644 index d7b67fe..0000000 --- a/src/test/java/cc/sukazyo/cono/morny/util/TestCommonFormat.java +++ /dev/null @@ -1,36 +0,0 @@ -package cc.sukazyo.cono.morny.util; - -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; - -import static cc.sukazyo.cono.morny.util.CommonFormat.*; -import static org.junit.jupiter.api.Assertions.assertEquals; - -public class TestCommonFormat { - - @ParameterizedTest - @CsvSource(textBlock = """ - 1664646870402, 8, 2022-10-02 01:54:30:402 - 1, 8, 1970-01-01 08:00:00:001 - 0, -1, 1969-12-31 23:00:00:000 - """ - ) - void testFormatDate (long timestamp, int utfOffset, String expectedHumanReadableTime) { - assertEquals(expectedHumanReadableTime, formatDate(timestamp, utfOffset)); - } - - @ParameterizedTest - @CsvSource(textBlock = """ - 100, '100ms' - 3000, '3s 0ms' - 326117522, '3d 18h 35min 17s 522ms' - 53373805, 14h 49min 33s 805ms - """) -// -1, '-1ms' // WARN: maybe sometime an unexpected usage -// -194271974291, '-291ms' // -// """) // - void testFormatDuration (long durationMillis, String humanReadableDuration) { - assertEquals(humanReadableDuration, formatDuration(durationMillis)); - } - -} diff --git a/src/test/scala/cc/sukazyo/cono/morny/MornyCLI.scala b/src/test/scala/cc/sukazyo/cono/morny/MornyCLI.scala new file mode 100644 index 0000000..a5c01f8 --- /dev/null +++ b/src/test/scala/cc/sukazyo/cono/morny/MornyCLI.scala @@ -0,0 +1,12 @@ +package cc.sukazyo.cono.morny + +import cc.sukazyo.cono.morny.util.UniversalCommand + +import scala.io.StdIn + +@main def MornyCLI (): Unit = { + + print("$ java -jar morny-coeur-\"+MornySystem.VERSION_FULL+\".jar ") + ServerMain main UniversalCommand(StdIn readLine) + +} diff --git a/src/test/scala/cc/sukazyo/cono/morny/test/MornyTests.scala b/src/test/scala/cc/sukazyo/cono/morny/test/MornyTests.scala new file mode 100644 index 0000000..8d62c60 --- /dev/null +++ b/src/test/scala/cc/sukazyo/cono/morny/test/MornyTests.scala @@ -0,0 +1,10 @@ +package cc.sukazyo.cono.morny.test + +import org.scalatest.freespec.AnyFreeSpec +import org.scalatest.matchers.should + +abstract class MornyTests extends AnyFreeSpec with should.Matchers { + + val pending_val = "[not-implemented]" + +} diff --git a/src/test/scala/cc/sukazyo/cono/morny/test/utils/BiliToolTest.scala b/src/test/scala/cc/sukazyo/cono/morny/test/utils/BiliToolTest.scala new file mode 100644 index 0000000..1ae8264 --- /dev/null +++ b/src/test/scala/cc/sukazyo/cono/morny/test/utils/BiliToolTest.scala @@ -0,0 +1,68 @@ +package cc.sukazyo.cono.morny.test.utils + +import cc.sukazyo.cono.morny.test.MornyTests +import org.scalatest.prop.TableDrivenPropertyChecks + +import scala.util.Random + +class BiliToolTest extends MornyTests with TableDrivenPropertyChecks { + + private val examples = Table( + ("bv", "av"), + ("17x411w7KC", 170001L), + ("1Q541167Qg", 455017605L), + ("1mK4y1C7Bz", 882584971L), + ("1T24y197V2", 688730800L), + ) + + forAll (examples) { (bv, av) => s"while using av$av/BV$bv :" - { + import cc.sukazyo.cono.morny.util.BiliTool.{toAv, toBv} + "av to bv works" in { toBv(av) shouldEqual bv } + "bv to av works" in { toAv(bv) shouldEqual av } + }} + + "BV with unsupported length :" - { + import cc.sukazyo.cono.morny.util.BiliTool.{toAv, IllegalFormatException} + val examples = Table( + "bv", + "12345", + "12345678", + "123456789", +// "1234567890", length 10 which is supported + "1234567890a", + "1234567890ab", + "1234567890abcdef" + ) + forAll(examples) { bv => + s"length ${bv.length} should throws IllegalFormatException" in: + an [IllegalFormatException] should be thrownBy toAv(bv) + } + } + + "BV with special character :" - { + val examples = Table( + ("bv" , "contains_special"), + ("1mK4O1C7Bz", "O"), + ("1m04m1C7Bz", "0"), + ("1mK4O1I7Bz", "I"), + ("1mK4O1C7Bl", "l"), + ("1--4O1C7Bl", "[symbols]") + ) + import cc.sukazyo.cono.morny.util.BiliTool.{toAv, IllegalFormatException} + forAll(examples) { (bv, with_sp) => + s"'$with_sp' should throws IllegalFormatException" in: + an [IllegalFormatException] should be thrownBy toAv(bv) + } + } + + "av/bv converting should be reversible" in { + for (_ <- 1 to 20) { + val rand_av = Random.between(0, 999999999L) + import cc.sukazyo.cono.morny.util.BiliTool.{toAv, toBv} + val my_bv = toBv(rand_av) + toAv(my_bv) shouldEqual rand_av + toBv(toAv(my_bv)) shouldEqual my_bv + } + } + +} diff --git a/src/test/scala/cc/sukazyo/cono/morny/test/utils/CommonEncryptTest.scala b/src/test/scala/cc/sukazyo/cono/morny/test/utils/CommonEncryptTest.scala new file mode 100644 index 0000000..8557661 --- /dev/null +++ b/src/test/scala/cc/sukazyo/cono/morny/test/utils/CommonEncryptTest.scala @@ -0,0 +1,33 @@ +package cc.sukazyo.cono.morny.test.utils + +import cc.sukazyo.cono.morny.test.MornyTests +import org.scalatest.prop.TableDrivenPropertyChecks + +class CommonEncryptTest extends MornyTests with TableDrivenPropertyChecks { + + "while doing hash :" - { + + val examples = Table( + ("md5" , "text"), + ("28be57d368b75051da76c068a6733284", "莲子"), + ("9644c5cbae223013228cd528817ba4f5", "莲子\n"), + ("d41d8cd98f00b204e9800998ecf8427e", "") + ) + + import cc.sukazyo.cono.morny.util.CommonEncrypt.MD5 + import cc.sukazyo.cono.morny.util.ConvertByteHex.toHex + forAll (examples) { (md5, text) => + s"while hashing text \"$text\" :" - { + + s"the MD5 value should be $md5" in { MD5(text).toHex shouldEqual md5 } + + "other algorithms" in pending + + } + } + + s"while hashing binary file $pending_val" in pending + + } + +} diff --git a/src/test/scala/cc/sukazyo/cono/morny/test/utils/CommonFormatTest.scala b/src/test/scala/cc/sukazyo/cono/morny/test/utils/CommonFormatTest.scala new file mode 100644 index 0000000..33dac4f --- /dev/null +++ b/src/test/scala/cc/sukazyo/cono/morny/test/utils/CommonFormatTest.scala @@ -0,0 +1,46 @@ +package cc.sukazyo.cono.morny.test.utils + +import cc.sukazyo.cono.morny.test.MornyTests +import cc.sukazyo.cono.morny.util.CommonFormat.{formatDate, formatDuration} +import org.scalatest.prop.TableDrivenPropertyChecks + +class CommonFormatTest extends MornyTests with TableDrivenPropertyChecks { + + "while using #formatDate :" - { + + val examples = Table( + ("time_text" , "timestamp", "zone_offset"), + ("2022-10-02 01:54:30:402", 1664646870402L, 8), + ("1970-01-01 08:00:00:001", 1L, 8), + ("1969-12-31 23:00:00:000", 0L, -1), + ) + + forAll(examples) { (time_text, timestamp, zone_offset) => + s"time $time_text in TimeZone($zone_offset) should be UTC timestamp $timestamp" in: + formatDate(timestamp, zone_offset) shouldEqual time_text + } + + } + + "while using #formatDuration :" - { + + val examples = Table( + ("time_millis", "duration_text"), + (100L , "100ms"), + (3000L , "3s 0ms"), + (326117522L , "3d 18h 35min 17s 522ms"), + (53373805L , "14h 49min 33s 805ms"), + (3600001L , "1h 0min 0s 1ms") + ) + + forAll(examples) { (time_millis, duration_text) => + + s"duration ($time_millis) millis should be formatted to '$duration_text'" in: + formatDuration(time_millis) shouldEqual duration_text + 0 should equal (0) + + } + + } + +} diff --git a/src/test/scala/cc/sukazyo/cono/morny/test/utils/ConvertByteHexTest.scala b/src/test/scala/cc/sukazyo/cono/morny/test/utils/ConvertByteHexTest.scala new file mode 100644 index 0000000..25aea93 --- /dev/null +++ b/src/test/scala/cc/sukazyo/cono/morny/test/utils/ConvertByteHexTest.scala @@ -0,0 +1,45 @@ +package cc.sukazyo.cono.morny.test.utils + +import cc.sukazyo.cono.morny.test.MornyTests +import org.scalatest.prop.TableDrivenPropertyChecks + +class ConvertByteHexTest extends MornyTests with TableDrivenPropertyChecks { + + private val examples_hex = Table( + ("byte" , "hex"), + ( 0x00 toByte, "00"), + ( 0x01 toByte, "01"), + ( 0x20 toByte, "20"), + ( 0x77 toByte, "77"), + (-0x60 toByte, "a0"), + ( 0x0a toByte, "0a"), + (-0x01 toByte, "ff"), + ( 0xfb toByte, "fb"), + ) + + "while using Byte#toHex :" - forAll (examples_hex) ((byte, hex) => { + s"byte ($byte) should be hex '$hex''" in { + import cc.sukazyo.cono.morny.util.ConvertByteHex.toHex + (byte toHex) shouldEqual hex + } + }) + + private val examples_hexs = Table( + ("bytes", "hex"), + (Array[Byte](0x00), "00"), + (Array[Byte](0xff toByte), "ff"), + (Array[Byte](0xc3 toByte), "c3"), + (Array[Byte](), ""), + (Array[Byte](0x30,0x0a,0x00,0x04,0xb0.toByte,0x00), "300a0004b000"), + (Array[Byte](0x00,0x00,0x0a,0xff.toByte,0xfc.toByte,0xab.toByte,0x00.toByte,0x04), "00000afffcab0004"), + (Array[Byte](0x00,0x7c,0x11,0x28,0x88.toByte,0xa6.toByte,0xfc.toByte,0x30), "007c112888a6fc30"), + ) + + "while using Array[Byte]#toHex :" - forAll(examples_hexs) ((bytes, hex) => { + s"byte array(${bytes mkString ","}) should be hex string $hex" in { + import cc.sukazyo.cono.morny.util.ConvertByteHex.toHex + (bytes toHex) shouldEqual hex + } + }) + +} diff --git a/src/test/scala/cc/sukazyo/cono/morny/test/utils/FileUtilsTest.scala b/src/test/scala/cc/sukazyo/cono/morny/test/utils/FileUtilsTest.scala new file mode 100644 index 0000000..1873d12 --- /dev/null +++ b/src/test/scala/cc/sukazyo/cono/morny/test/utils/FileUtilsTest.scala @@ -0,0 +1,9 @@ +package cc.sukazyo.cono.morny.test.utils + +import cc.sukazyo.cono.morny.test.MornyTests + +class FileUtilsTest extends MornyTests { + + "while getting the MD5 hash of a file :" in pending + +} diff --git a/src/test/scala/cc/sukazyo/cono/morny/test/utils/UniversalCommandTest.scala b/src/test/scala/cc/sukazyo/cono/morny/test/utils/UniversalCommandTest.scala new file mode 100644 index 0000000..28a11c5 --- /dev/null +++ b/src/test/scala/cc/sukazyo/cono/morny/test/utils/UniversalCommandTest.scala @@ -0,0 +1,75 @@ +package cc.sukazyo.cono.morny.test.utils + +import cc.sukazyo.cono.morny.test.MornyTests +import org.scalatest.matchers.should.Matchers +import org.scalatest.prop.TableDrivenPropertyChecks + +class UniversalCommandTest extends MornyTests with Matchers with TableDrivenPropertyChecks { + + "while formatting command from String :" - { + + import cc.sukazyo.cono.morny.util.UniversalCommand as Cmd + + raw"args should be separated by (\u0020) ascii-space" in: + Cmd("a b c delta e") shouldEqual Array("a", "b", "c", "delta", "e"); + "args should not be separated by non-ascii spaces" in: + Cmd("tests ダタ セト") shouldEqual Array("tests", "ダタ セト"); + "multiple ascii-spaces should not generate empty arg in middle" in: + Cmd("tests some of data") shouldEqual Array("tests", "some", "of", "data"); + + """texts and ascii-spaces in '' should grouped in one arg""" in: + Cmd("""tests 'data set'""") shouldEqual Array("tests", "data set"); + """texts and ascii-spaces in "" should grouped in one arg""" in : + Cmd("""tests "data set"""") shouldEqual Array("tests", "data set"); + """mixed ' and " should throws IllegalArgumentsException""" in: + an [IllegalArgumentException] should be thrownBy Cmd("""tests "data set' "of it'"""); + "with ' not closed should throws IllegalArgumentException" in: + an [IllegalArgumentException] should be thrownBy Cmd("""use 'it """); + + raw"\ should escape itself" in: + Cmd(raw"input \\data") shouldEqual Array("input", "\\data"); + raw"\ should escape ascii-space, makes it processed as a normal character" in: + Cmd(raw"input data\ set") shouldEqual Array("input", "data set"); + raw"\ should escape ascii-space, makes it can be an arg body" in: + Cmd(raw"input \ some-thing") shouldEqual Array("input", " ", "some-thing"); + raw"""\ should escape "", makes it processed as a normal character""" in : + Cmd(raw"""use \"inputted""") shouldEqual Array("use", "\"inputted"); + raw"\ should escape '', makes it processed as a normal character" in: + Cmd(raw"use \'inputted") shouldEqual Array("use", "'inputted"); + raw"\ should escape itself which inside a quoted scope" in: + Cmd(raw"use 'quoted \\ body'") shouldEqual Array("use", "quoted \\ body"); + raw"""\ should escape " which inside a "" scope""" in: + Cmd(raw"""in "quoted \" body" body""") shouldEqual Array("in", "quoted \" body", "body"); + raw"""\ should escape ' which inside a "" scope""" in : + Cmd(raw"""in "not-quoted \' body" body""") shouldEqual Array("in", "not-quoted ' body", "body"); + raw"""\ should escape ' which inside a '' scope""" in : + Cmd(raw"""in 'quoted \' body' body""") shouldEqual Array("in", "quoted ' body", "body"); + raw"""\ should escape " which inside a ' scope""" in : + Cmd(raw"""in 'not-quoted \" body' body""") shouldEqual Array("in", "not-quoted \" body", "body"); + raw"\ should not escape ascii-space which inside a quoted scope" in: + Cmd(raw"""'quoted \ do not escape' did""") shouldEqual Array(raw"quoted \ do not escape", "did"); + raw"with \ in the end should throws IllegalArgumentException" in: + an [IllegalArgumentException] should be thrownBy Cmd("something error!\\"); + + "with multi-line input should throws IllegalArgumentException" in: + an [IllegalArgumentException] should be thrownBy Cmd("something will\nhave a new line"); + + val example_special_character = Table( + "char", + " ", + "\t", + "\\t", + "\\a", + "/", + "&&", + "\\u1234", + ) + forAll(example_special_character) { char => + s"input with special character ($char) should keep origin like" in { + Cmd(s"$char dataset data[$char]contains parsed") shouldEqual + Array(char, "dataset", s"data[$char]contains", "parsed") + } + } + } + +} diff --git a/src/test/scala/cc/sukazyo/cono/morny/test/utils/tgapi/InputCommandTest.scala b/src/test/scala/cc/sukazyo/cono/morny/test/utils/tgapi/InputCommandTest.scala new file mode 100644 index 0000000..3baa038 --- /dev/null +++ b/src/test/scala/cc/sukazyo/cono/morny/test/utils/tgapi/InputCommandTest.scala @@ -0,0 +1,22 @@ +package cc.sukazyo.cono.morny.test.utils.tgapi + +import cc.sukazyo.cono.morny.test.MornyTests + +class InputCommandTest extends MornyTests { + + "while create new InputCommand :" - { + + s"while input is $pending_val:" - { + + s"command should be $pending_val" in pending + s"target should be $pending_val" in pending + + "args array should always exists" in pending + + s"args should parsed to array $pending_val" in pending + + } + + } + +} diff --git a/src/test/scala/cc/sukazyo/cono/morny/test/utils/tgapi/formatting/NamingUtilsTest.scala b/src/test/scala/cc/sukazyo/cono/morny/test/utils/tgapi/formatting/NamingUtilsTest.scala new file mode 100644 index 0000000..883d8aa --- /dev/null +++ b/src/test/scala/cc/sukazyo/cono/morny/test/utils/tgapi/formatting/NamingUtilsTest.scala @@ -0,0 +1,27 @@ +package cc.sukazyo.cono.morny.test.utils.tgapi.formatting + +import cc.sukazyo.cono.morny.test.MornyTests + +class NamingUtilsTest extends MornyTests { + + "while generating inline query result id :" - { + + "while not use no data :" - { + + "(different tag) should return different id" in pending + "(same tag) should return the same id" in pending + + } + + "while use data :" - { + + "(same tag) with (same data) should return the same id" in pending + "(same tag) with (different data) should return different id" in pending + "(different tag) with (same data) should return different id" in pending + "change tag and data position should return different id" in pending + + } + + } + +} diff --git a/src/test/scala/cc/sukazyo/cono/morny/test/utils/tgapi/formatting/TelegramFormatterTest.scala b/src/test/scala/cc/sukazyo/cono/morny/test/utils/tgapi/formatting/TelegramFormatterTest.scala new file mode 100644 index 0000000..1fbd912 --- /dev/null +++ b/src/test/scala/cc/sukazyo/cono/morny/test/utils/tgapi/formatting/TelegramFormatterTest.scala @@ -0,0 +1,9 @@ +package cc.sukazyo.cono.morny.test.utils.tgapi.formatting + +import cc.sukazyo.cono.morny.test.MornyTests + +class TelegramFormatterTest extends MornyTests { + + "some test" in pending + +} diff --git a/src/test/scala/cc/sukazyo/cono/morny/test/utils/tgapi/formatting/TelegramParseEscapeTest.scala b/src/test/scala/cc/sukazyo/cono/morny/test/utils/tgapi/formatting/TelegramParseEscapeTest.scala new file mode 100644 index 0000000..eb3f7da --- /dev/null +++ b/src/test/scala/cc/sukazyo/cono/morny/test/utils/tgapi/formatting/TelegramParseEscapeTest.scala @@ -0,0 +1,25 @@ +package cc.sukazyo.cono.morny.test.utils.tgapi.formatting + +import cc.sukazyo.cono.morny.test.MornyTests + +class TelegramParseEscapeTest extends MornyTests { + + "while escape HTML document :" - { + + import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramParseEscape.escapeHtml as h + val any_other = "0ir0Q*%_\"ir[0\"#*I%T\"I{EtjpJGI{\")#W*IT}P%*IH#){#NIJB9-/q{$(Jg'9m]q|MH4j0hq}|+($NR{')}}" + + "& must be escaped" in: + h("a & b") shouldEqual "a & b" + "< and > must be escaped" in: + h("") shouldEqual "<data-error>" + "& and < and > must all be escaped" in: + h(" && ") shouldEqual "<some-a> && <some-b>" + "space and count should be kept" in: + h("\t<<<< \n") shouldEqual "\t<<<< \n" + "any others should kept origin like" in: + h(any_other) shouldEqual any_other + + } + +} diff --git a/src/test/scala/cc/sukazyo/cono/morny/test/utils/tgapi/formatting/TelegramUserInformationTest.scala b/src/test/scala/cc/sukazyo/cono/morny/test/utils/tgapi/formatting/TelegramUserInformationTest.scala new file mode 100644 index 0000000..c839a5b --- /dev/null +++ b/src/test/scala/cc/sukazyo/cono/morny/test/utils/tgapi/formatting/TelegramUserInformationTest.scala @@ -0,0 +1,26 @@ +package cc.sukazyo.cono.morny.test.utils.tgapi.formatting + +import cc.sukazyo.cono.morny.test.MornyTests +import org.scalatest.prop.TableDrivenPropertyChecks +import org.scalatest.tagobjects.{Network, Slow} + +class TelegramUserInformationTest extends MornyTests with TableDrivenPropertyChecks { + + private val examples_telegram_cdn = Table( + ("username", "cdn"), + ("Eyre_S", "cdn5"), + ) + + forAll(examples_telegram_cdn) ((username, cdn) => s"while user is @$username :" - { + + import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramUserInformation.* + + s"datacenter should be $cdn" taggedAs (Slow, Network) in: + getDataCenterFromUser(username) shouldEqual cdn + + "formatted data should as expected" in: + pending + + }) + +} diff --git a/src/test/scala/live/LiveMain.scala b/src/test/scala/live/LiveMain.scala new file mode 100644 index 0000000..2b7de09 --- /dev/null +++ b/src/test/scala/live/LiveMain.scala @@ -0,0 +1,9 @@ +package live + +import cc.sukazyo.cono.morny.test.utils.BiliToolTest + +@main def LiveMain (args: String*): Unit = { + + org.scalatest.run(BiliToolTest()) + +} From 6e822274477d36501f3cd78ad45d82c871cdec6b Mon Sep 17 00:00:00 2001 From: Eyre_S Date: Sun, 17 Sep 2023 15:18:57 +0800 Subject: [PATCH 5/5] bug fix for scala port --- .gitignore | 1 + gradle.properties | 2 +- .../scala/cc/sukazyo/cono/morny/MornySystem.scala | 1 + .../cono/morny/bot/command/DirectMsgClear.scala | 4 ++++ .../cono/morny/bot/command/MornyInformation.scala | 9 ++++++--- .../cono/morny/bot/command/MornyOldJrrp.scala | 2 +- .../cc/sukazyo/cono/morny/bot/command/Nbnhhsh.scala | 6 +++--- .../cc/sukazyo/cono/morny/bot/command/喵呜.scala | 6 +++--- .../cc/sukazyo/cono/morny/bot/command/私わね.scala | 1 + .../cc/sukazyo/cono/morny/bot/event/OnCallMe.scala | 2 ++ .../cono/morny/bot/event/OnEventHackHandle.scala | 4 ++-- .../cono/morny/bot/event/OnQuestionMarkReply.scala | 12 +++++++++--- .../cono/morny/bot/event/OnTelegramCommand.scala | 2 +- .../sukazyo/cono/morny/bot/event/OnUserRandom.scala | 8 +++++--- .../cono/morny/bot/event/OnUserSlashAction.scala | 12 +++++++++++- .../sukazyo/cono/morny/bot/query/MyInformation.scala | 2 +- .../cono/morny/bot/query/ShareToolTwitter.scala | 12 ++++++------ .../cc/sukazyo/cono/morny/daemon/MornyReport.scala | 1 + .../scala/cc/sukazyo/cono/morny/data/MornyJrrp.scala | 2 +- .../cono/morny/data/ip186/IP186QueryHandler.scala | 1 + .../sukazyo/cono/morny/internal/ScalaJavaConv.scala | 12 ------------ .../sukazyo/cono/morny/util/UniversalCommand.scala | 3 +-- .../sukazyo/cono/morny/util/tgapi/ExtraAction.java | 2 +- .../util/tgapi/formatting/TelegramFormatter.scala | 4 ++++ .../tgapi/formatting/TelegramUserInformation.scala | 4 ++-- 25 files changed, 69 insertions(+), 46 deletions(-) delete mode 100644 src/main/scala/cc/sukazyo/cono/morny/internal/ScalaJavaConv.scala diff --git a/.gitignore b/.gitignore index f9ff432..f02e4e8 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ #build /build/ /bin/ +/out/ .metals/ .bloop/ .project diff --git a/gradle.properties b/gradle.properties index 1a9ee69..f7385a5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,7 +5,7 @@ MORNY_ARCHIVE_NAME = morny-coeur MORNY_CODE_STORE = https://github.com/Eyre-S/Coeur-Morny-Cono MORNY_COMMIT_PATH = https://github.com/Eyre-S/Coeur-Morny-Cono/commit/%s -VERSION = 1.0.0-RC4 +VERSION = 1.0.0-RC5 USE_DELTA = true VERSION_DELTA = scalaport4 diff --git a/src/main/scala/cc/sukazyo/cono/morny/MornySystem.scala b/src/main/scala/cc/sukazyo/cono/morny/MornySystem.scala index 7e052eb..b355595 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/MornySystem.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/MornySystem.scala @@ -17,6 +17,7 @@ object MornySystem { @BuildConfigField val VERSION_DELTA: String = BuildConfig.VERSION_DELTA @BuildConfigField val CODENAME: String = BuildConfig.CODENAME @BuildConfigField val CODE_STORE: String = BuildConfig.CODE_STORE + //noinspection ScalaWeakerAccess @BuildConfigField val COMMIT_PATH: String = BuildConfig.COMMIT_PATH @BuildConfigField 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 7971d95..fb01c86 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 @@ -25,6 +25,10 @@ object DirectMsgClear extends ISimpleCommand { logger trace "message is not outdated(48 hrs ago)" val isTrusted = MornyCoeur.trusted isTrusted event.message.from.id + // todo: + // it does not work. due to the Telegram Bot API doesn't provide + // nested replyToMessage, so currently the trusted check by + // replyToMessage.replyToMessage will not work! def _isReplyTrusted: Boolean = if (event.message.replyToMessage.replyToMessage == null) false else if (event.message.replyToMessage.replyToMessage.from.id == event.message.from.id) true 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 516ddd7..8a55bc7 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 @@ -14,6 +14,7 @@ import java.net.InetAddress import java.rmi.UnknownHostException import scala.language.postfixOps +// todo: maybe move some utils method outside object MornyInformation extends ITelegramCommand { private case object Subs { @@ -46,6 +47,7 @@ object MornyInformation extends ITelegramCommand { } + //noinspection ScalaWeakerAccess def getVersionGitTagHTML: String = { if (!MornySystem.isGitBuild) return "" val g = StringBuilder() @@ -61,11 +63,12 @@ object MornyInformation extends ITelegramCommand { val v = StringBuilder() v ++= s"${MornySystem VERSION_BASE}" if (MornySystem isUseDelta) v++=s"-δ${MornySystem VERSION_DELTA}" - if (MornySystem isGitBuild) v++="+"++=getVersionGitTagHTML + if (MornySystem isGitBuild) v++="+git."++=getVersionGitTagHTML v ++= s"*${MornySystem.CODENAME toUpperCase}" v toString } + //noinspection ScalaWeakerAccess def getRuntimeHostname: String|Null = { try InetAddress.getLocalHost.getHostName catch case _:UnknownHostException => null @@ -154,13 +157,13 @@ object MornyInformation extends ITelegramCommand { event.message.chat.id, /* language=html */ s"""system: - |- Morny ${h(if (getRuntimeHostname == null) "" else getRuntimeHostname)} + |- ${h(if (getRuntimeHostname == null) "" else getRuntimeHostname)} |- ${h(sysprop("os.name"))} ${h(sysprop("os.arch"))} ${h(sysprop("os.version"))} |java runtime: |- ${h(sysprop("java.vm.vendor"))}.${h(sysprop("java.vm.name"))} |- ${h(sysprop("java.vm.version"))} |vm memory: - |- ${Runtime.getRuntime.totalMemory/1024/1024} / ${Runtime.getRuntime.maxMemory/1024/1024} + |- ${Runtime.getRuntime.totalMemory/1024/1024} / ${Runtime.getRuntime.maxMemory/1024/1024} MB |- ${Runtime.getRuntime.availableProcessors} cores |coeur version: |- $getVersionAllFullTagHTML 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 index 327d7df..c859f14 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyOldJrrp.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/MornyOldJrrp.scala @@ -28,7 +28,7 @@ object MornyOldJrrp extends ITelegramCommand { MornyCoeur.extra exec SendMessage( event.message.chat.id, // language=html - f"${user.fullnameRefHTML} 在(utc的)今天的运气指数是———— $jrrp%.2f%%${h(ending)}" + f"${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 4d7e343..32e6819 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 @@ -25,10 +25,10 @@ object Nbnhhsh extends ITelegramCommand { override def execute (using command: InputCommand, event: Update): Unit = { val queryTarget: String|Null = - if (event.message.replyToMessage != null && event.message.replyToMessage.text != null) - event.message.replyToMessage.text - else if command.args nonEmpty then + if command.args nonEmpty then command.args mkString " " + else if (event.message.replyToMessage != null && event.message.replyToMessage.text != null) + event.message.replyToMessage.text else null if (queryTarget == null) 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 bf36bab..109077e 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/command/喵呜.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/喵呜.scala @@ -3,15 +3,15 @@ package cc.sukazyo.cono.morny.bot.command import cc.sukazyo.cono.morny.MornyCoeur import cc.sukazyo.cono.morny.data.TelegramStickers import cc.sukazyo.cono.morny.util.tgapi.InputCommand -import com.pengrad.telegrambot.model.request.ParseMode import com.pengrad.telegrambot.model.{Message, Update} +import com.pengrad.telegrambot.model.request.ParseMode import com.pengrad.telegrambot.request.{SendMessage, SendSticker} import javax.swing.text.html.HTML import scala.annotation.unused import scala.language.postfixOps -@SuppressWarnings(Array("NonAsciiCharacters")) +//noinspection NonAsciiCharacters object 喵呜 { object 抱抱 extends ISimpleCommand { @@ -56,7 +56,7 @@ object 喵呜 { } private def replyingSet (whileRec: String, whileNew: String)(using event: Update): Unit = { - val isNew = event.message.replyToMessage == null; + val isNew = event.message.replyToMessage == null val target = if (isNew) event.message else event.message.replyToMessage MornyCoeur.extra exec new SendMessage( event.message.chat.id, 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 8696bb8..5321657 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/command/私わね.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/私わね.scala @@ -7,6 +7,7 @@ import cc.sukazyo.cono.morny.util.UseRandom.* import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.request.SendMessage +//noinspection NonAsciiCharacters object 私わね extends ISimpleCommand { override val name: String = "me" 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 a8d16b3..07f4d96 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 @@ -52,6 +52,8 @@ object OnCallMe extends EventListener { var isAllowed = false var lastDinnerData: Message|Null = null if (MornyCoeur.trusted isTrusted_dinnerReader req.from.id) { + // todo: have issues + // i dont want to test it anymore... it might be deprecated soon lastDinnerData = (MornyCoeur.extra exec GetChat(MornyCoeur.config.dinnerChatId)).chat.pinnedMessage val sendResp = MornyCoeur.extra exec ForwardMessage( req.from.id, 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 index 121b3ef..f42d9e9 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnEventHackHandle.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnEventHackHandle.scala @@ -52,9 +52,9 @@ object OnEventHackHandle extends EventListener { 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) + onEventHacked(update.channelPost.chat.id, 0) override def onEditedChannelPost (using update: Update): Boolean = - onEventHacked(update.editedChannelPost.chat.id, update.editedChannelPost.from.id) + onEventHacked(update.editedChannelPost.chat.id, 0) override def onInlineQuery (using update: Update): Boolean = onEventHacked(0, update.inlineQuery.from.id) override def onChosenInlineResult (using update: Update): Boolean = 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 index 601cafc..3d73a09 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnQuestionMarkReply.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnQuestionMarkReply.scala @@ -9,7 +9,14 @@ import scala.language.postfixOps object OnQuestionMarkReply extends EventListener { - private def QUESTION_MARKS = Set('?', '?', '¿', '⁈', '⁇', '‽', '❔', '❓') + private val QUESTION_MARKS = Set('?', '?', '¿', '⁈', '⁇', '‽', '❔', '❓') + + def isAllMessageMark (using text: String): Boolean = { + var isAll = true + for (c <- text) + if !(QUESTION_MARKS contains c) then isAll = false + isAll + } override def onMessage (using event: Update): Boolean = { @@ -18,8 +25,7 @@ object OnQuestionMarkReply extends EventListener { import cc.sukazyo.cono.morny.util.UseMath.over import cc.sukazyo.cono.morny.util.UseRandom.chance_is if (1 over 8) chance_is false then return false - for (c <- event.message.text toCharArray) - if !(QUESTION_MARKS contains c) then return false + if !isAllMessageMark(using event.message.text) then return false MornyCoeur.extra exec SendMessage( event.message.chat.id, event.message.text 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 index a2ef6ea..a850f21 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnTelegramCommand.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/event/OnTelegramCommand.scala @@ -22,7 +22,7 @@ object OnTelegramCommand extends EventListener { if (!(inputCommand.command matches "^\\w+$")) logger debug "not command" false - else if ((inputCommand.target ne null) && (inputCommand.target ne MornyCoeur.username)) + else if ((inputCommand.target ne null) && (inputCommand.target != MornyCoeur.username)) logger debug "not morny command" false else 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 df18cb7..e47f3ce 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 @@ -9,13 +9,13 @@ import scala.language.postfixOps object OnUserRandom extends EventListener { - private val USER_OR_QUERY = "(.+)(?:还是|or)(.+)"r - private val USER_IF_QUERY = "(.+)[吗?|?]+$"r + private val USER_OR_QUERY = "^(.+)(?:还是|or)(.+)$"r + private val USER_IF_QUERY = "^(.+)(?:吗\\?|?|\\?|吗?)$"r override def onMessage(using update: Update): Boolean = { if update.message.text == null then return false - if update.message.text startsWith "/" then return false + if !(update.message.text startsWith "/") then return false import cc.sukazyo.cono.morny.util.UseRandom.rand_half val query = update.message.text substring 1 @@ -23,6 +23,8 @@ object OnUserRandom extends EventListener { case USER_OR_QUERY(_con1, _con2) => if rand_half then _con1 else _con2 case USER_IF_QUERY(_con) => + // for capability with [[OnQuestionMarkReply]] + if OnQuestionMarkReply.isAllMessageMark(using _con) then return false (if rand_half then "不" else "") + _con case _ => null 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 1778dfc..db80040 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 @@ -22,14 +22,24 @@ object OnUserSlashAction extends EventListener { if (text startsWith "/") { + // there has to be some special conditions for DP7 + // due to I have left DP7, I closed those special + // conditions. + // that is 2022, May 28th + // when one year goes, These code have rewrite with + // scala, those commented code is removed permanently. + // these message, here to remember the old DP7. + val actions = UniversalCommand(text) actions(0) = actions(0) substring 1 actions(0) actions(0) match + // ignore Telegram command like case TG_FORMAT(_) => return false + // ignore Path link case x if x contains "/" => return false case _ => @@ -55,7 +65,7 @@ object OnUserSlashAction extends EventListener { h(v_verb), if hasObject then "" else "了", if (origin == target) s"自己" - else origin.sender_firstnameRefHTML, + else target.sender_firstnameRefHTML, if hasObject then h(v_object+" ") else "" ) ).parseMode(ParseMode HTML).replyToMessageId(update.message.messageId) 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 b6066e0..2c8aa58 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 @@ -14,7 +14,7 @@ object MyInformation extends ITelegramQuery { override def query (event: Update): List[InlineQueryUnit[_]] | Null = { - if ((event.inlineQuery.query ne null) || (event.inlineQuery.query nonEmpty)) return null + if !((event.inlineQuery.query eq null) || (event.inlineQuery.query isEmpty)) then return null List( InlineQueryUnit(InlineQueryResultArticle( 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 572c32e..baff446 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 @@ -9,11 +9,11 @@ import scala.util.matching.Regex object ShareToolTwitter extends ITelegramQuery { - val TITLE_VX = "[tweet] Share as VxTwitter" - val TITLE_VX_COMBINED = "[tweet] Share as VxTwitter(combination)" - val ID_PREFIX_VX = "[morny/share/twitter/vxtwi]" - val ID_PREFIX_VX_COMBINED = "[morny/share/twitter/vxtwi_combine]" - val REGEX_TWEET_LINK: Regex = "^(?:https?://)?((?:(?:c\\.)?vx|fx|www\\.)?twitter\\.com)/((\\w+)/status/(\\d+)(?:/photo/(\\d+))?)/?(\\?[\\w&=-]+)?$"r + private val TITLE_VX = "[tweet] Share as VxTwitter" + private val TITLE_VX_COMBINED = "[tweet] Share as VxTwitter(combination)" + private val ID_PREFIX_VX = "[morny/share/twitter/vxtwi]" + private val ID_PREFIX_VX_COMBINED = "[morny/share/twitter/vxtwi_combine]" + private val REGEX_TWEET_LINK: Regex = "^(?:https?://)?((?:(?:c\\.)?vx|fx|www\\.)?twitter\\.com)/((\\w+)/status/(\\d+)(?:/photo/(\\d+))?)/?(\\?[\\w&=-]+)?$"r override def query (event: Update): List[InlineQueryUnit[_]] | Null = { @@ -21,7 +21,7 @@ object ShareToolTwitter extends ITelegramQuery { event.inlineQuery.query match - case REGEX_TWEET_LINK(_1, _2, _) => + case REGEX_TWEET_LINK(_, _2, _, _, _, _) => List( InlineQueryUnit(InlineQueryResultArticle( inlineQueryId(ID_PREFIX_VX+event.inlineQuery.query), TITLE_VX, diff --git a/src/main/scala/cc/sukazyo/cono/morny/daemon/MornyReport.scala b/src/main/scala/cc/sukazyo/cono/morny/daemon/MornyReport.scala index 9591fb1..7d39431 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/daemon/MornyReport.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/daemon/MornyReport.scala @@ -74,6 +74,7 @@ object MornyReport { ).parseMode(ParseMode HTML)) } + //noinspection ScalaWeakerAccess def sectionConfigFields (config: MornyConfig): String = { val echo = StringBuilder() for (field <- config.getClass.getFields) { diff --git a/src/main/scala/cc/sukazyo/cono/morny/data/MornyJrrp.scala b/src/main/scala/cc/sukazyo/cono/morny/data/MornyJrrp.scala index d6ec709..b707576 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/data/MornyJrrp.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/data/MornyJrrp.scala @@ -12,6 +12,6 @@ object MornyJrrp { private def jrrp_v_xmomi (identifier: Long, dayStamp: Long): Double = import cc.sukazyo.cono.morny.util.CommonEncrypt.MD5 import cc.sukazyo.cono.morny.util.ConvertByteHex.toHex - (java.lang.Long parseLong MD5(s"$identifier@$dayStamp").toHex.substring(0, 4)) / (0xffff toDouble) + java.lang.Long.parseLong(MD5(s"$identifier@$dayStamp").toHex.substring(0, 4), 16) / (0xffff toDouble) } 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 f9dc533..d045cc5 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 @@ -19,6 +19,7 @@ object IP186QueryHandler { commonQuery(SITE_URL + ip, QUERY_PARAM_IP) @throws[IOException] + //noinspection ScalaWeakerAccess def query_whois (domain: String): IP186Response = commonQuery(SITE_URL+"whois/"+domain, QUERY_PARAM_WHOIS) diff --git a/src/main/scala/cc/sukazyo/cono/morny/internal/ScalaJavaConv.scala b/src/main/scala/cc/sukazyo/cono/morny/internal/ScalaJavaConv.scala deleted file mode 100644 index 3547a2b..0000000 --- a/src/main/scala/cc/sukazyo/cono/morny/internal/ScalaJavaConv.scala +++ /dev/null @@ -1,12 +0,0 @@ -package cc.sukazyo.cono.morny.internal - -import scala.jdk.CollectionConverters._ -import scala.collection.immutable as simm -import java.util as j - -object ScalaJavaConv { - - def jSetInteger2simm (data: j.Set[Integer]): simm.Set[Int] = - data.asScala.toSet.map(_.intValue) - -} diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/UniversalCommand.scala b/src/main/scala/cc/sukazyo/cono/morny/util/UniversalCommand.scala index 65a1e87..9aa6e5c 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/util/UniversalCommand.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/util/UniversalCommand.scala @@ -36,8 +36,7 @@ object UniversalCommand { arg = arg.empty } else if (input(i) isQuote) { val _inside_tag = input(i) - var _inside = true - boundary { while (_inside) { + boundary { while (true) { i=i+1 if (i >= input.length) throw IllegalArgumentException("UniversalCommand: unclosed quoted text") if (input(i) == _inside_tag) diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/ExtraAction.java b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/ExtraAction.java index 784e6c6..b7f19ee 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/ExtraAction.java +++ b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/ExtraAction.java @@ -32,7 +32,7 @@ public class ExtraAction { public , R extends BaseResponse> R exec (T req, String errorMessage) { final R resp = bot.execute(req); if (!resp.isOk()) throw new EventRuntimeException.ActionFailed( - (errorMessage.equals("") ? String.valueOf(resp.errorCode()) : errorMessage), + (errorMessage.isEmpty() ? String.valueOf(resp.errorCode()) : errorMessage), resp ); return resp; diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramFormatter.scala b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramFormatter.scala index acc0d49..48fd6ef 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramFormatter.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramFormatter.scala @@ -22,6 +22,7 @@ object TelegramFormatter { case _ => s"@[c/${chat.id}]" else s"@${h(chat.username)}" + //noinspection ScalaWeakerAccess def safe_firstnameRefHTML: String = chat.`type` match // language=html @@ -29,6 +30,7 @@ object TelegramFormatter { // language=html case _ => s"${h(chat.title)}" + //noinspection ScalaWeakerAccess def id_tdLib: Long = if chat.id < 0 then (chat.id - MASK_BOTAPI_ID)abs else chat.id @@ -42,12 +44,14 @@ object TelegramFormatter { extension (user: User) { + //noinspection ScalaWeakerAccess def fullname: String = _connectName(user.firstName, user.lastName) def fullnameRefHTML: String = // language=html s"${h(user.fullname)}" + //noinspection ScalaWeakerAccess def firstnameRefHTML: String = // language=html s"${h(user.firstName)}" diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramUserInformation.scala b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramUserInformation.scala index 81d87ee..88a9501 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramUserInformation.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramUserInformation.scala @@ -9,8 +9,8 @@ import scala.util.Using object TelegramUserInformation { - val DC_QUERY_SOURCE_SITE = "https://t.me/" - val DC_QUERY_PROCESSOR_REGEX: Regex = "(cdn[1-9]).tele(sco.pe|gram-cdn.org)"r + private val DC_QUERY_SOURCE_SITE = "https://t.me/" + private val DC_QUERY_PROCESSOR_REGEX: Regex = "(cdn[1-9]).tele(sco.pe|gram-cdn.org)"r private val httpClient = OkHttpClient()