From c2de1b8748406a534c459fc67839f49c87015bb4 Mon Sep 17 00:00:00 2001 From: Eyre_S Date: Sun, 6 Nov 2022 17:52:48 +0800 Subject: [PATCH 01/14] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BA=86=20MornyConfig?= =?UTF-8?q?=20=E4=BB=A5=E5=8F=8A=E4=BF=AE=E6=94=B9=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E5=9F=BA=E4=BA=8E=20MornyConfig?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 6 +- .../cono/morny/GradleProjectConfigures.java | 6 +- .../cc/sukazyo/cono/morny/MornyCoeur.java | 101 +++++-------- .../cc/sukazyo/cono/morny/MornyConfig.java | 137 ++++++++++++++++++ .../cc/sukazyo/cono/morny/MornyTrusted.java | 35 ++--- .../cc/sukazyo/cono/morny/ServerMain.java | 70 ++++----- .../cono/morny/bot/event/OnCallMe.java | 7 +- .../event/OnUpdateTimestampOffsetLock.java | 4 +- 8 files changed, 225 insertions(+), 141 deletions(-) create mode 100644 src/main/java/cc/sukazyo/cono/morny/MornyConfig.java diff --git a/gradle.properties b/gradle.properties index 338d93f..0684f5b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,12 +1,12 @@ ## Core -VERSION = 0.8.0.11 +VERSION = 1.0.0-alpha1 -CODENAME = putian +CODENAME = beiping # dependencies -libSpotbugsVersion = 4.7.2 +libSpotbugsVersion = 4.7.3 libMessivaVersion = 0.1.0.1 diff --git a/src/main/java/cc/sukazyo/cono/morny/GradleProjectConfigures.java b/src/main/java/cc/sukazyo/cono/morny/GradleProjectConfigures.java index 8735b7d..459f791 100644 --- a/src/main/java/cc/sukazyo/cono/morny/GradleProjectConfigures.java +++ b/src/main/java/cc/sukazyo/cono/morny/GradleProjectConfigures.java @@ -4,7 +4,7 @@ package cc.sukazyo.cono.morny; * the final field that will be updated by gradle automatically. */ public class GradleProjectConfigures { - public static final String VERSION = "0.8.0.11"; - public static final String CODENAME = "putian"; - public static final long COMPILE_TIMESTAMP = 1667376095614L; + public static final String VERSION = "1.0.0-alpha1"; + public static final String CODENAME = "beiping"; + public static final long COMPILE_TIMESTAMP = 1667581079623L; } diff --git a/src/main/java/cc/sukazyo/cono/morny/MornyCoeur.java b/src/main/java/cc/sukazyo/cono/morny/MornyCoeur.java index 9c0cee9..452d0e4 100644 --- a/src/main/java/cc/sukazyo/cono/morny/MornyCoeur.java +++ b/src/main/java/cc/sukazyo/cono/morny/MornyCoeur.java @@ -14,7 +14,6 @@ import com.pengrad.telegrambot.request.GetMe; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import java.util.Set; import static cc.sukazyo.cono.morny.Log.logger; @@ -27,6 +26,9 @@ public class MornyCoeur { /** 当前程序的 Morny Coeur 实例 */ private static MornyCoeur INSTANCE; + /** 当前 Morny 的启动配置 */ + public final MornyConfig config; + /** 当前 Morny 的{@link MornyTrusted 信任验证机}实例 */ private final MornyTrusted trusted; /** 当前 Morny 的 telegram 命令管理器 */ @@ -36,7 +38,6 @@ public class MornyCoeur { /** morny 的 bot 账户 */ private final TelegramBot account; private final ExtraAction extraActionInstance; - private final boolean isRemoveCommandListWhenExit; /** * morny 的 bot 账户的用户名
*
@@ -53,58 +54,36 @@ public class MornyCoeur { * 这个字段将会在登陆成功后赋值为登录到的 bot 的 id。 */ public final long userid; - /** - * morny 的事件忽略前缀时间
- *
- * {@link cc.sukazyo.cono.morny.bot.event.OnUpdateTimestampOffsetLock} - * 会根据这里定义的时间戳取消掉比此时间更早的事件链 - */ - public final long latestEventTimestamp; /** * morny 主程序启动时间
* 用于统计数据 */ - public static final long coeurStartTimestamp = System.currentTimeMillis(); - - public static final long DINNER_CHAT_ID = -1001707106392L; + public static final long coeurStartTimestamp = ServerMain.systemStartupTime; private record LogInResult(TelegramBot account, String username, long userid) { } /** * 执行 bot 初始化 * - * @param botKey bot 的 telegram bot api token - * @param botUsername bot 的 username 限定。如果为 null 则表示不限定, - * 如果指定,则登录时会检查所登陆的 bot 的用户名是否与此相等 - * @param master morny 实例所信任的主人的 id。用于初始化 {@link #trusted} - * @param trustedChat morny 实例所信任的群组的 id。用于初始化 {@link #trusted} - * @param latestEventTimestamp 事件处理器会处理事件的最早时间戳 —— - * 只有限定的 message 事件会受此影响。 - * 单位为毫秒 + * @param config Morny 实例的配置选项数据 */ - private MornyCoeur ( - @Nullable String botApi, @Nullable String botApi4File, - @Nonnull String botKey, @Nullable String botUsername, - long master, long trustedChat, Set trustedRDinner, - long latestEventTimestamp, - boolean isRemoveCommandListWhenExit - ) { + private MornyCoeur (MornyConfig config) { + + this.config = config; - this.latestEventTimestamp = latestEventTimestamp; - this.isRemoveCommandListWhenExit = isRemoveCommandListWhenExit; configureSafeExit(); - logger.info("args key:\n " + botKey); - if (botUsername != null) { - logger.info("login as:\n " + botUsername); + logger.info("args key:\n " + config.telegramBotKey); + if (config.telegramBotUsername != null) { + logger.info("login as:\n " + config.telegramBotUsername); } try { - final LogInResult loginResult = login(botApi, botApi4File, botKey, botUsername); + 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(master, trustedChat, trustedRDinner); + this.trusted = new MornyTrusted(this); StringBuilder trustedReadersDinnerIds = new StringBuilder(); trusted.getTrustedReadersOfDinnerSet().forEach(id -> trustedReadersDinnerIds.append("\n ").append(id)); logger.info(String.format(""" @@ -114,7 +93,7 @@ public class MornyCoeur { - trusted chat (id) %d - trusted reader-of-dinner (id)%s""", - master, trustedChat, trustedReadersDinnerIds + config.trustedMaster, config.trustedChat, trustedReadersDinnerIds )); } catch (Exception e) { @@ -135,32 +114,28 @@ public class MornyCoeur { * 如果 morny 已经初始化,则不会进行初始化,抛出错误消息并直接退出方法。 * * @see #MornyCoeur 程序初始化方法 + * @param config morny 实例的配置选项数据 */ - public static void main ( - @Nullable String botApi, @Nullable String botApi4File, - @Nonnull String botKey, @Nullable String botUsername, - long master, long trustedChat, Set trustedRDinner, long latestEventTimestamp, - boolean isAutomaticResetCommandList, boolean isRemoveCommandListWhenExit - ) { + public static void main (MornyConfig config) { if (INSTANCE == null) { + logger.info("Coeur Starting"); - INSTANCE = new MornyCoeur( - botApi, botApi4File, - botKey, botUsername, - master, trustedChat, trustedRDinner, - latestEventTimestamp, - isRemoveCommandListWhenExit - ); + INSTANCE = new MornyCoeur(config); + MornyDaemons.start(); + logger.info("start telegram events listening"); EventListeners.registerAllListeners(); INSTANCE.account.setUpdatesListener(OnUpdate::onNormalUpdate); - if (isAutomaticResetCommandList) { + + if (config.commandLoginRefresh) { logger.info("resetting telegram command list"); commandManager().automaticUpdateList(); } + logger.info("Coeur start complete"); return; + } logger.error("Coeur already started!!!"); } @@ -179,7 +154,7 @@ public class MornyCoeur { private void exitCleanup () { logger.info("clean:save tracker data."); MornyDaemons.stop(); - if (isRemoveCommandListWhenExit) { + if (config.commandLogoutClear) { commandManager.automaticRemoveList(); } } @@ -192,16 +167,20 @@ public class MornyCoeur { } /** - * 登录 bot
- *
+ * 登录 bot. + *

* 会反复尝试三次进行登录。如果登录失败,则会直接抛出 RuntimeException 结束处理。 * 会通过 GetMe 动作验证是否连接上了 telegram api 服务器, * 同时也要求登录获得的 username 和 {@link #username} 声明值相等 * - * @param api bot client 将会连接到的 telegram bot api 位置 - * @param api4File bot client 将会连接到的 telegram file api 位置,如果不指定则会跟随 {@code api} 选项的设定 - * @param key bot 的 api-token - * @param requireName 要求登录到的需要的 username,如果登陆后的 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 @@ -281,13 +260,13 @@ public class MornyCoeur { } /** + * 获取当前 morny 的配置数据 * - * 获取忽略时间点 - * - * @return {@link #latestEventTimestamp MornyCoeur.latestEventTimestamp} + * @return {@link #config MornyCoeur.config} */ - public static long getLatestEventTimestamp () { - return INSTANCE.latestEventTimestamp; + @Nonnull + public static MornyConfig config () { + return INSTANCE.config; } /** diff --git a/src/main/java/cc/sukazyo/cono/morny/MornyConfig.java b/src/main/java/cc/sukazyo/cono/morny/MornyConfig.java new file mode 100644 index 0000000..004302c --- /dev/null +++ b/src/main/java/cc/sukazyo/cono/morny/MornyConfig.java @@ -0,0 +1,137 @@ +package cc.sukazyo.cono.morny; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.HashSet; +import java.util.Set; + +public class MornyConfig { + + /* ======================================= * + * Config props Names Definition * + * ======================================= */ + + public static final String PROP_TOKEN_KEY_DEFAULT = "TELEGRAM_BOT_API_TOKEN"; + public static final String PROP_TOKEN_MORNY_KEY = "MORNY_TG_TOKEN"; + public static final String[] PROP_TOKEN_KEY = {PROP_TOKEN_KEY_DEFAULT, PROP_TOKEN_MORNY_KEY}; + + /* ======================================= * + * telegram bot login config * + * ======================================= */ + + /** + * Morny Telegram 使用的 API 服务器. + *

+ * 不设定的话,默认将会使用 {@code https://api.telegram.org/bot} + */ + @Nullable public final String telegramBotApiServer; + /** + * Morny Telegram 使用的 API 服务器的 file 服务路径. + *

+ * 不设定的话,默认将会使用 {@value com.pengrad.telegrambot.impl.FileApi#FILE_API} + */ + @Nullable public final String telegramBotApiServer4File; + + /** + * morny 使用的 telegram bot 的 bot api token. + *

+ * 这个值必须设定。 + */ + @Nonnull public final String telegramBotKey; + /** + * morny 所使用的 bot 的 username. + *

+ * 如果设定了这个值,则在 morny 登录 bot 时将会检查所登录的 bot 的 username 是否和这里设定的 username 匹配。 + * 如果不匹配,则会拒绝登录然后报错。 + *

+ * 如果没有设定这个值,则不会对登录 bot 的 username 进行限制。 + */ + @Nullable public final String telegramBotUsername; + + /* ======================================= * + * morny trusted config * + * ======================================= */ + + /** + * morny 的主人. + *

+ * 这项值的对象总是会被{@link MornyTrusted 信任管理器}认为是可信任的 + */ + public final long trustedMaster; + /** + * morny 可信群聊的 id. + *

+ * {@link MornyTrusted 信任管理器}将会认为这个群聊中的所有拥有 + * {@link com.pengrad.telegrambot.model.ChatMember.Status#administrator administrator} 权限的成员是可信任的。 + *

+ * id 需要符合 bot api 标准。 + */ + public final long trustedChat; + + /* ======================================= * + * system: event ignore * + * ======================================= */ + + public final boolean eventIgnoreOutdated; + /** + * morny 的事件忽略前缀时间
+ *
+ * {@link cc.sukazyo.cono.morny.bot.event.OnUpdateTimestampOffsetLock} + * 会根据这里定义的时间戳取消掉比此时间更早的事件链 + */ + public final long eventOutdatedTimestamp; + + /* ======================================= * + * system: command list automation * + * ======================================= */ + + public final boolean commandLoginRefresh; + public final boolean commandLogoutClear; + + /* ======================================= * + * function: dinner query tool * + * ======================================= */ + + @Nonnull public final Set dinnerTrustedReaders; + public final long dinnerChatId; + + public MornyConfig (@Nonnull Prototype prototype) throws CheckFailure { + this.telegramBotApiServer = prototype.telegramBotApiServer; + this.telegramBotApiServer4File = prototype.telegramBotApiServer4File; + if (prototype.telegramBotKey == null) throw new CheckFailure.NullTelegramBotKey(); + this.telegramBotKey = prototype.telegramBotKey; + this.telegramBotUsername = prototype.telegramBotUsername; + this.trustedMaster = prototype.trustedMaster; + this.trustedChat = prototype.trustedChat; + this.eventIgnoreOutdated = prototype.eventIgnoreOutdated; + if (prototype.eventOutdatedTimestamp < 1) throw new CheckFailure.UnsetEventOutdatedTimestamp(); + this.eventOutdatedTimestamp = prototype.eventOutdatedTimestamp; + this.commandLoginRefresh = prototype.commandLoginRefresh; + this.commandLogoutClear = prototype.commandLogoutClear; + this.dinnerTrustedReaders = prototype.dinnerTrustedReaders; + this.dinnerChatId = prototype.dinnerChatId; + } + + public static class CheckFailure extends Exception { + public static class NullTelegramBotKey extends CheckFailure {} + public static class UnsetEventOutdatedTimestamp extends CheckFailure {} + } + + public static class Prototype { + + @Nullable public String telegramBotApiServer = null; + @Nullable public String telegramBotApiServer4File = null; + @Nullable public String telegramBotKey = null; + @Nullable public String telegramBotUsername = null; + public long trustedMaster = 793274677L; + public long trustedChat = -1001541451710L; + public boolean eventIgnoreOutdated = false; + public long eventOutdatedTimestamp = -1; + public boolean commandLoginRefresh = false; + public boolean commandLogoutClear = false; + @Nonnull public Set dinnerTrustedReaders = new HashSet<>(); + public long dinnerChatId = -1001707106392L; + + } + +} diff --git a/src/main/java/cc/sukazyo/cono/morny/MornyTrusted.java b/src/main/java/cc/sukazyo/cono/morny/MornyTrusted.java index ba93789..ae2b3bb 100644 --- a/src/main/java/cc/sukazyo/cono/morny/MornyTrusted.java +++ b/src/main/java/cc/sukazyo/cono/morny/MornyTrusted.java @@ -1,7 +1,7 @@ package cc.sukazyo.cono.morny; import com.pengrad.telegrambot.model.ChatMember.Status; -import java.util.HashSet; + import java.util.Set; /** @@ -9,27 +9,10 @@ import java.util.Set; */ public class MornyTrusted { - /** - * 群聊id,其指向的群聊指示了哪个群的成员是受信任的 - * @see #isTrusted(long) 受信检查 - */ - public final Long TRUSTED_CHAT_ID; + private final MornyCoeur instance; - /** - * morny 的主人
- * 这项值的对象总是会被认为是可信任的 - */ - public final long MASTER; - - private final Set TRUSTED_READERS_OF_DINNER; - - public MornyTrusted (long master, long trustedChatId, Set trustedRDinner) { - this.TRUSTED_CHAT_ID = trustedChatId; - this.MASTER = master; - this.TRUSTED_READERS_OF_DINNER = new HashSet<>(){{ - this.add(master); - this.addAll(trustedRDinner); - }}; + public MornyTrusted (MornyCoeur instance) { + this.instance = instance; } /** @@ -37,22 +20,22 @@ public class MornyTrusted { *
* 用户需要受信任才能执行一些对程序甚至是宿主环境而言危险的操作,例如关闭程序
*
- * 它的逻辑(目前)是检查群聊 {@link #TRUSTED_CHAT_ID} 中这个用户是否为群组管理员 + * 它的逻辑(目前)是检查群聊 {@link MornyConfig#trustedChat} 中这个用户是否为群组管理员 * * @param userId 需要检查的用户的id * @return 所传递的用户id对应的用户是否受信任 */ public boolean isTrusted (long userId) { - if (userId == MASTER) return true; - return MornyCoeur.extra().isUserInGroup(userId, TRUSTED_CHAT_ID, Status.administrator); + if (userId == instance.config.trustedMaster) return true; + return MornyCoeur.extra().isUserInGroup(userId, instance.config.trustedChat, Status.administrator); } public boolean isTrustedForDinnerRead (long userId) { - return TRUSTED_READERS_OF_DINNER.contains(userId); + return instance.config.dinnerTrustedReaders.contains(userId); } public Set getTrustedReadersOfDinnerSet () { - return Set.copyOf(TRUSTED_READERS_OF_DINNER); + return Set.copyOf(instance.config.dinnerTrustedReaders); } } diff --git a/src/main/java/cc/sukazyo/cono/morny/ServerMain.java b/src/main/java/cc/sukazyo/cono/morny/ServerMain.java index 17a831f..7e6f6ac 100644 --- a/src/main/java/cc/sukazyo/cono/morny/ServerMain.java +++ b/src/main/java/cc/sukazyo/cono/morny/ServerMain.java @@ -4,9 +4,6 @@ import cc.sukazyo.cono.morny.util.CommonFormat; import javax.annotation.Nonnull; -import java.util.HashSet; -import java.util.Set; - import static cc.sukazyo.cono.morny.Log.logger; /** @@ -18,8 +15,7 @@ import static cc.sukazyo.cono.morny.Log.logger; */ public class ServerMain { - public static final String PROP_TOKEN_KEY = "TELEGRAM_BOT_API_TOKEN"; - public static final String PROP_TOKEN_MORNY_KEY = "MORNY_TG_TOKEN"; + public static final long systemStartupTime = System.currentTimeMillis(); private static final String THREAD_MORNY_INIT = "morny-init"; @@ -57,7 +53,7 @@ public class ServerMain { * 与 {@code --only-hello} 参数不兼容 —— 会导致程序完全没有任何输出 * *

  • - * {@code --outdated-block} 会使得 {@link MornyCoeur#latestEventTimestamp} + * {@code --outdated-block} 会使得 {@link MornyConfig#eventIgnoreOutdated} * 赋值为程序启动的时间,从而造成阻挡程序启动之前的消息事件处理效果。 *
  • *
  • @@ -85,20 +81,12 @@ public class ServerMain { //# //# 启动参数设置区块 //# - + final MornyConfig.Prototype config = new MornyConfig.Prototype(); boolean versionEchoMode = false; boolean welcomeEchoMode = false; boolean showWelcome = true; - String key = null; - String username = null; - boolean outdatedBlock = false; - long master = 793274677L; - Set trustedReadersOfDinner = new HashSet<>(); - long trustedChat = -1001541451710L; - boolean autoCmdList = false; - boolean autoCmdRemove = false; - String api = null; - String api4File = null; + + config.eventOutdatedTimestamp = systemStartupTime; for (int i = 0; i < args.length; i++) { @@ -106,7 +94,7 @@ public class ServerMain { switch (args[i]) { case "--outdated-block", "-ob" -> { - outdatedBlock = true; + config.eventIgnoreOutdated = true; continue; } case "--no-hello", "-hf", "--quiet", "-q" -> { @@ -123,51 +111,51 @@ public class ServerMain { } case "--token", "-t" -> { i++; - key = args[i]; + config.telegramBotKey = args[i]; continue; } case "--username", "-u" -> { i++; - username = args[i]; + config.telegramBotUsername = args[i]; continue; } case "--master", "-mm" -> { i++; - master = Long.parseLong(args[i]); + config.trustedMaster = Long.parseLong(args[i]); continue; } case "--trusted-chat", "-trs" -> { i++; - trustedChat = Long.parseLong(args[i]); + config.trustedChat = Long.parseLong(args[i]); continue; } //noinspection SpellCheckingInspection case "--trusted-reader-dinner", "-trsd" -> { i++; - trustedReadersOfDinner.add(Long.parseLong(args[i])); + config.dinnerTrustedReaders.add(Long.parseLong(args[i])); continue; } case "--auto-cmd", "-cmd", "-c" -> { - autoCmdList = true; - autoCmdRemove = true; + config.commandLoginRefresh = true; + config.commandLogoutClear = true; continue; } case "--auto-cmd-list", "-ca" -> { - autoCmdList = true; + config.commandLoginRefresh = true; continue; } case "--auto-cmd-remove", "-cr" -> { - autoCmdRemove = true; + config.commandLogoutClear = true; continue; } case "--api", "-a" -> { i++; - api = args[i]; + config.telegramBotApiServer = args[i]; continue; } case "--api-files", "files-api", "-af" -> { i++; - api4File = args[i]; + config.telegramBotApiServer4File = args[i]; continue; } } @@ -180,7 +168,7 @@ public class ServerMain { String propToken = null; String propTokenKey = null; - for (String iKey : new String[]{PROP_TOKEN_KEY, PROP_TOKEN_MORNY_KEY}) { + for (String iKey : MornyConfig.PROP_TOKEN_KEY) { if (System.getenv(iKey) != null) { propToken = System.getenv(iKey); propTokenKey = iKey; @@ -228,21 +216,19 @@ public class ServerMain { //# if (propToken != null) { - key = propToken; + config.telegramBotKey = propToken; logger.info("Parameter set by EnvVar $"+propTokenKey); } - if (key == null) { - logger.info("Parameter required has no value:\n --token."); - return; - } + Thread.currentThread().setName(THREAD_MORNY_INIT); - MornyCoeur.main( - api, api4File, - key, username, - master, trustedChat, trustedReadersOfDinner, - outdatedBlock?System.currentTimeMillis():0, - autoCmdList, autoCmdRemove - ); + try { + MornyCoeur.main(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/event/OnCallMe.java b/src/main/java/cc/sukazyo/cono/morny/bot/event/OnCallMe.java index c448881..89ed0fc 100644 --- a/src/main/java/cc/sukazyo/cono/morny/bot/event/OnCallMe.java +++ b/src/main/java/cc/sukazyo/cono/morny/bot/event/OnCallMe.java @@ -1,7 +1,6 @@ package cc.sukazyo.cono.morny.bot.event; import cc.sukazyo.cono.morny.MornyCoeur; -import cc.sukazyo.cono.morny.MornyTrusted; import cc.sukazyo.cono.morny.bot.api.EventListener; import cc.sukazyo.cono.morny.data.TelegramStickers; import cc.sukazyo.cono.morny.util.CommonFormat; @@ -27,10 +26,10 @@ public class OnCallMe extends EventListener { /** * 主人的 telegram user id,同时被用于 chat id
    - * 跟随 {@link MornyTrusted#MASTER} 的值 + * 跟随 {@link cc.sukazyo.cono.morny.MornyConfig#trustedMaster} 的值 * @since 0.4.2.1 */ - private static final long ME = MornyCoeur.trustedInstance().MASTER; + private static final long ME = MornyCoeur.config().trustedMaster; /** * 监听私聊 bot 的消息进行呼叫关键字匹配。 @@ -112,7 +111,7 @@ public class OnCallMe extends EventListener { boolean isAllowed = false; Message lastDinnerData = null; if (MornyCoeur.trustedInstance().isTrustedForDinnerRead(event.message().from().id())) { - lastDinnerData = MornyCoeur.extra().exec(new GetChat(MornyCoeur.DINNER_CHAT_ID)).chat().pinnedMessage(); + 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(), diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/event/OnUpdateTimestampOffsetLock.java b/src/main/java/cc/sukazyo/cono/morny/bot/event/OnUpdateTimestampOffsetLock.java index 80eff7f..faee77f 100644 --- a/src/main/java/cc/sukazyo/cono/morny/bot/event/OnUpdateTimestampOffsetLock.java +++ b/src/main/java/cc/sukazyo/cono/morny/bot/event/OnUpdateTimestampOffsetLock.java @@ -7,7 +7,7 @@ import com.pengrad.telegrambot.model.Update; import javax.annotation.Nonnull; /** - * 阻止 {@link MornyCoeur#latestEventTimestamp 指定时间} 之前的事件处理. + * 阻止 {@link cc.sukazyo.cono.morny.MornyConfig#eventOutdatedTimestamp 指定时间} 之前的事件处理. *

    * 只支持以下事件 *

      @@ -27,7 +27,7 @@ public class OnUpdateTimestampOffsetLock extends EventListener { * @since 0.4.2.7 */ public boolean isOutdated(long timestamp) { - return timestamp < MornyCoeur.getLatestEventTimestamp()/1000; + return timestamp < MornyCoeur.config().eventOutdatedTimestamp/1000; } @Override From e3c273b370f341191c24bc82114e788c5d2acf8d Mon Sep 17 00:00:00 2001 From: Eyre_S Date: Sun, 6 Nov 2022 20:07:11 +0800 Subject: [PATCH 02/14] =?UTF-8?q?=E5=B0=86=20GradleProjectConfigures=20?= =?UTF-8?q?=E5=8F=98=E6=9B=B4=E4=B8=BA=E4=BD=BF=E7=94=A8=20BuildConfig=20?= =?UTF-8?q?=E5=B7=A5=E5=85=B7=EF=BC=8C=E6=B7=BB=E5=8A=A0=E4=BA=86=20versio?= =?UTF-8?q?n=5Fdelta?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - archiveBaseName 更名为 'morny-coeur' - 现在在 getJarMd5 时遇到文件读写错误不会再输出错误堆栈信息了 - gradle 基本的参数化 --- .gitignore | 1 + build.gradle | 64 +++++++++++-------- gradle.properties | 7 +- .../cono/morny/GradleProjectConfigures.java | 10 --- .../cc/sukazyo/cono/morny/MornySystem.java | 5 +- .../cc/sukazyo/cono/morny/ServerMain.java | 6 +- .../cono/morny/bot/command/MornyCommands.java | 10 +-- .../java/cc/sukazyo/cono/morny/MornyCLI.java | 2 +- 8 files changed, 57 insertions(+), 48 deletions(-) delete mode 100644 src/main/java/cc/sukazyo/cono/morny/GradleProjectConfigures.java diff --git a/.gitignore b/.gitignore index 881a611..df3d0f1 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ /build/ /bin/ .project +lcoal.properties # debug dir /run/ diff --git a/build.gradle b/build.gradle index 0e2a6aa..d721443 100644 --- a/build.gradle +++ b/build.gradle @@ -1,16 +1,33 @@ +import java.nio.charset.Charset +import java.nio.charset.StandardCharsets + plugins { id 'java' id 'java-library' id 'maven-publish' id 'application' id 'com.github.johnrengelman.shadow' version '7.1.0' + id 'com.github.gmazzo.buildconfig' version '3.1.0' } -group 'cc.sukazyo' -version VERSION -project.ext.archiveBaseName = 'Coeur_Morny_Cono' -project.ext.artifactId = 'morny-coeur' -mainClassName = 'cc.sukazyo.cono.morny.ServerMain' +final String proj_group = 'cc.sukazyo' +final String proj_package = "${proj_group}.cono.morny" +final String proj_archive_name = MORNY_ARCHIVE_NAME + +final String proj_version_base = VERSION +final String proj_version_delta = VERSION_DELTA +final String proj_version_use_delta = Boolean.parseBoolean(VERSION_DELTA) +final String proj_version = proj_version_base + (proj_version_use_delta ? "-δ${proj_version_delta}" : "") +final String proj_version_codename = CODENAME + +final JavaVersion proj_java = JavaVersion.VERSION_17 +final Charset proj_file_encoding = StandardCharsets.UTF_8 + +group proj_group +version proj_version +project.ext.archiveBaseName = proj_archive_name +project.ext.artifactId = proj_archive_name +mainClassName = "${proj_package}.ServerMain" repositories { mavenCentral() @@ -31,47 +48,44 @@ dependencies { } -task updateVersionCode { - ant.replaceregexp(match:'VERSION = ["a-zA-Z0-9.\\-_+@]+;', replace:"VERSION = \"$project.version\";", flags:'g', byline:true) { - fileset(dir: 'src/main/java/cc/sukazyo/cono/morny', includes: 'GradleProjectConfigures.java') - } - ant.replaceregexp(match:'CODENAME = ["a-zA-Z0-9]+;', replace:"CODENAME = \"${CODENAME}\";", flags:'g', byline:true) { - fileset(dir: 'src/main/java/cc/sukazyo/cono/morny', includes: 'GradleProjectConfigures.java') - } - ant.replaceregexp(match:'COMPILE_TIMESTAMP = [0-9]+L;', replace:"COMPILE_TIMESTAMP = ${System.currentTimeMillis()}L;", flags:'g', byline:true) { - fileset(dir: 'src/main/java/cc/sukazyo/cono/morny', includes: 'GradleProjectConfigures.java') - } -} - -compileJava.dependsOn updateVersionCode - test { useJUnitPlatform() } java { - sourceCompatibility JavaVersion.VERSION_17 - targetCompatibility JavaVersion.VERSION_17 + sourceCompatibility proj_java + targetCompatibility proj_java withSourcesJar() } tasks.withType(JavaCompile) { - options.encoding = "UTF-8" + options.encoding = proj_file_encoding.name() } tasks.withType(Javadoc) { - options.encoding = 'UTF-8' - options.docEncoding = 'UTF-8' - options.charSet = 'UTF-8' + options.encoding = proj_file_encoding.name() + options.docEncoding = proj_file_encoding.name() + options.charSet = proj_file_encoding.name() } tasks.test { useJUnitPlatform() } +buildConfig { + + packageName(proj_package) + + buildConfigField('String', 'VERSION', "\"${proj_version}\"") + buildConfigField('String', 'VERSION_DELTA', "\"${proj_version_delta}\"") + buildConfigField('String', 'CODENAME', "\"${proj_version_codename}\"") + buildConfigField('long', 'COMPILE_TIMESTAMP', "${System.currentTimeMillis()}L") + +} + shadowJar { archiveBaseName.set("${project.ext.archiveBaseName}") archiveVersion.set("${project.version}") diff --git a/gradle.properties b/gradle.properties index 0684f5b..b65028a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,11 @@ ## Core -VERSION = 1.0.0-alpha1 +MORNY_ARCHIVE_NAME = morny-coeur + +VERSION = 1.0.0-alpha2 + +USE_DELTA = true +VERSION_DELTA = 11061900 CODENAME = beiping diff --git a/src/main/java/cc/sukazyo/cono/morny/GradleProjectConfigures.java b/src/main/java/cc/sukazyo/cono/morny/GradleProjectConfigures.java deleted file mode 100644 index 459f791..0000000 --- a/src/main/java/cc/sukazyo/cono/morny/GradleProjectConfigures.java +++ /dev/null @@ -1,10 +0,0 @@ -package cc.sukazyo.cono.morny; - -/** - * the final field that will be updated by gradle automatically. - */ -public class GradleProjectConfigures { - public static final String VERSION = "1.0.0-alpha1"; - public static final String CODENAME = "beiping"; - public static final long COMPILE_TIMESTAMP = 1667581079623L; -} diff --git a/src/main/java/cc/sukazyo/cono/morny/MornySystem.java b/src/main/java/cc/sukazyo/cono/morny/MornySystem.java index e9a486d..a62290e 100644 --- a/src/main/java/cc/sukazyo/cono/morny/MornySystem.java +++ b/src/main/java/cc/sukazyo/cono/morny/MornySystem.java @@ -16,7 +16,7 @@ public class MornySystem { * 程序的语义化版本号
      * 会由 gradle 任务 {@code updateVersionCode} 更新 */ - public static final String VERSION = GradleProjectConfigures.VERSION; + public static final String VERSION = BuildConfig.VERSION; /** * Morny Coeur 当前的版本代号.
      @@ -26,7 +26,7 @@ public class MornySystem { *
      * 会由 gradle 任务 {@code updateVersionCode} 更新 */ - public static final String CODENAME = GradleProjectConfigures.CODENAME; + public static final String CODENAME = BuildConfig.CODENAME; /** * 获取程序 jar 文件的 md5-hash 值
      @@ -43,7 +43,6 @@ public class MornySystem { try { return FileUtils.getMD5Three(MornyCoeur.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()); } catch (IOException | URISyntaxException e) { - e.printStackTrace(System.out); return ""; } catch (NoSuchAlgorithmException e) { e.printStackTrace(System.out); diff --git a/src/main/java/cc/sukazyo/cono/morny/ServerMain.java b/src/main/java/cc/sukazyo/cono/morny/ServerMain.java index 7e6f6ac..2e330b2 100644 --- a/src/main/java/cc/sukazyo/cono/morny/ServerMain.java +++ b/src/main/java/cc/sukazyo/cono/morny/ServerMain.java @@ -192,8 +192,8 @@ public class ServerMain { %s [UTC]""", MornySystem.VERSION, MornySystem.CODENAME.toUpperCase(), MornySystem.getJarMd5(), - GradleProjectConfigures.COMPILE_TIMESTAMP, - CommonFormat.formatDate(GradleProjectConfigures.COMPILE_TIMESTAMP, 0) + BuildConfig.COMPILE_TIMESTAMP, + CommonFormat.formatDate(BuildConfig.COMPILE_TIMESTAMP, 0) )); return; @@ -207,7 +207,7 @@ public class ServerMain { - version %s (%s)(%d) - Morny %s""", MornySystem.VERSION, - MornySystem.getJarMd5(), GradleProjectConfigures.COMPILE_TIMESTAMP, + MornySystem.getJarMd5(), BuildConfig.COMPILE_TIMESTAMP, MornySystem.CODENAME.toUpperCase() )); diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyCommands.java b/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyCommands.java index 7b37258..4bbe09c 100644 --- a/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyCommands.java +++ b/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyCommands.java @@ -1,6 +1,6 @@ package cc.sukazyo.cono.morny.bot.command; -import cc.sukazyo.cono.morny.GradleProjectConfigures; +import cc.sukazyo.cono.morny.BuildConfig; import cc.sukazyo.cono.morny.MornyCoeur; import cc.sukazyo.cono.morny.MornySystem; import cc.sukazyo.cono.morny.data.MornyJrrp; @@ -249,8 +249,8 @@ public class MornyCommands { escapeHtml(MornySystem.CODENAME.toUpperCase()), escapeHtml(MornySystem.VERSION), escapeHtml(MornySystem.getJarMd5()), - GradleProjectConfigures.COMPILE_TIMESTAMP, - escapeHtml(formatDate(GradleProjectConfigures.COMPILE_TIMESTAMP, 0)) + BuildConfig.COMPILE_TIMESTAMP, + escapeHtml(formatDate(BuildConfig.COMPILE_TIMESTAMP, 0)) ) ).replyToMessageId(event.message().messageId()).parseMode(ParseMode.HTML)); } @@ -310,8 +310,8 @@ public class MornyCommands { escapeHtml(MornySystem.VERSION), escapeHtml(MornySystem.CODENAME), escapeHtml(MornySystem.getJarMd5()), - escapeHtml(formatDate(GradleProjectConfigures.COMPILE_TIMESTAMP, 0)), - GradleProjectConfigures.COMPILE_TIMESTAMP, + escapeHtml(formatDate(BuildConfig.COMPILE_TIMESTAMP, 0)), + BuildConfig.COMPILE_TIMESTAMP, // continuous escapeHtml(formatDuration(System.currentTimeMillis() - MornyCoeur.coeurStartTimestamp)), System.currentTimeMillis() - MornyCoeur.coeurStartTimestamp, diff --git a/src/test/java/cc/sukazyo/cono/morny/MornyCLI.java b/src/test/java/cc/sukazyo/cono/morny/MornyCLI.java index 1b6eea7..c26fca6 100644 --- a/src/test/java/cc/sukazyo/cono/morny/MornyCLI.java +++ b/src/test/java/cc/sukazyo/cono/morny/MornyCLI.java @@ -9,7 +9,7 @@ public class MornyCLI { public static void main (String[] args) { Scanner line = new Scanner(System.in); - System.out.print("$ java -jar morny-coeur-"+GradleProjectConfigures.VERSION+".jar " ); + System.out.print("$ java -jar morny-coeur-"+BuildConfig.VERSION+".jar " ); String x = line.nextLine(); ServerMain.main(UniversalCommand.format(x)); From 5dfe07f58630edd5d7086cc773c204ae28bbcc61 Mon Sep 17 00:00:00 2001 From: Eyre_S Date: Sun, 6 Nov 2022 21:31:24 +0800 Subject: [PATCH 03/14] =?UTF-8?q?=E7=89=88=E6=9C=AC=E5=8F=B7=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=20git=20commit=20=E6=A0=87=E7=AD=BE=E6=94=AF=E6=8C=81?= =?UTF-8?q?=EF=BC=8Cgradle=20build=20=E7=9A=84=20git=20=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E8=BE=93=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 58 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index d721443..ea2f560 100644 --- a/build.gradle +++ b/build.gradle @@ -1,3 +1,5 @@ +import org.ajoberstar.grgit.Status + import java.nio.charset.Charset import java.nio.charset.StandardCharsets @@ -8,6 +10,27 @@ plugins { id 'application' id 'com.github.johnrengelman.shadow' version '7.1.0' id 'com.github.gmazzo.buildconfig' version '3.1.0' + id 'org.ajoberstar.grgit' version '5.0.0' +} + +final boolean proj_git = grgit!=null +final String proj_commit = proj_git ? grgit.head().id : null +final boolean proj_clean = isCleanBuild() +if (!proj_git) + print "[MornyBuild] git repository not available for current working space! git version tag will be disabled." +else if (isCleanBuild()) { + print "git: clean build at ${grgit.head().id}" +} else { + final Status status = grgit.status() + println "git: non-clean-build" + if (!status.unstaged.allChanges.empty) { + println "git: unstaged changes" + listChanges(status.unstaged) + } + if (!status.staged.allChanges.empty) { + println "[MornyBuild] git: staged changes" + listChanges(status.staged) + } } final String proj_group = 'cc.sukazyo' @@ -17,7 +40,9 @@ final String proj_archive_name = MORNY_ARCHIVE_NAME final String proj_version_base = VERSION final String proj_version_delta = VERSION_DELTA final String proj_version_use_delta = Boolean.parseBoolean(VERSION_DELTA) -final String proj_version = proj_version_base + (proj_version_use_delta ? "-δ${proj_version_delta}" : "") +String proj_version = proj_version_base +if (proj_version_use_delta) proj_version += "-δ${proj_version_delta}" +if (proj_git) proj_version += "+git.${proj_commit.substring(0, 8)}" + (proj_clean?"":".δ") final String proj_version_codename = CODENAME final JavaVersion proj_java = JavaVersion.VERSION_17 @@ -79,10 +104,12 @@ buildConfig { packageName(proj_package) - buildConfigField('String', 'VERSION', "\"${proj_version}\"") - buildConfigField('String', 'VERSION_DELTA', "\"${proj_version_delta}\"") - buildConfigField('String', 'CODENAME', "\"${proj_version_codename}\"") - buildConfigField('long', 'COMPILE_TIMESTAMP', "${System.currentTimeMillis()}L") + buildConfigField('String', 'VERSION', "\"${proj_version}\"") + buildConfigField('String', 'VERSION_DELTA', "\"${proj_version_delta}\"") + buildConfigField('String', 'CODENAME', "\"${proj_version_codename}\"") + buildConfigField('long', 'COMPILE_TIMESTAMP', "${System.currentTimeMillis()}L") + buildConfigField('String', 'COMMIT', proj_git ? "\"${proj_commit}\"" : "null") + buildConfigField('boolean', 'CLEAN_BUILD', "${proj_clean}") } @@ -92,6 +119,27 @@ shadowJar { archiveClassifier.set("fat") } +@SuppressWarnings("all") +boolean isCleanBuild () { + if (grgit == null) return false + Set changes = grgit.status().unstaged.allChanges + grgit.status().staged.allChanges + for (String file in changes) { + if (file.startsWith("src/")) return false + if (file == "build.gradle") return false + if (file == "gradle.properties") return false + } + return true +} + +void listChanges (Status.Changes listing) { + for (String file in listing.added) + println " add: ${file}" + for (String file in listing.modified) + println " mod: ${file}" + for (String file in listing.removed) + println " del: ${file}" +} + publishing { repositories{ maven { From 3c7de7037d7976c58bcf02963bc730eba359c7f5 Mon Sep 17 00:00:00 2001 From: Eyre_S Date: Sun, 6 Nov 2022 21:43:15 +0800 Subject: [PATCH 04/14] =?UTF-8?q?=E5=B0=86=20COMPILE=5FTIMESTAMP=20?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=E5=9F=BA=E4=BA=8E=20commit=20time=20?= =?UTF-8?q?=E7=9A=84=20CODE=5FTIMESTAMP?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 3 ++- gradle.properties | 4 ++-- src/main/java/cc/sukazyo/cono/morny/ServerMain.java | 6 +++--- .../sukazyo/cono/morny/bot/command/MornyCommands.java | 10 +++++----- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/build.gradle b/build.gradle index ea2f560..c951ab2 100644 --- a/build.gradle +++ b/build.gradle @@ -44,6 +44,7 @@ String proj_version = proj_version_base if (proj_version_use_delta) proj_version += "-δ${proj_version_delta}" if (proj_git) proj_version += "+git.${proj_commit.substring(0, 8)}" + (proj_clean?"":".δ") final String proj_version_codename = CODENAME +final long proj_code_time = proj_clean ? grgit.head().dateTime.toInstant().toEpochMilli() : System.currentTimeMillis() final JavaVersion proj_java = JavaVersion.VERSION_17 final Charset proj_file_encoding = StandardCharsets.UTF_8 @@ -107,7 +108,7 @@ buildConfig { buildConfigField('String', 'VERSION', "\"${proj_version}\"") buildConfigField('String', 'VERSION_DELTA', "\"${proj_version_delta}\"") buildConfigField('String', 'CODENAME', "\"${proj_version_codename}\"") - buildConfigField('long', 'COMPILE_TIMESTAMP', "${System.currentTimeMillis()}L") + buildConfigField('long', 'CODE_TIMESTAMP', "${proj_code_time}L") buildConfigField('String', 'COMMIT', proj_git ? "\"${proj_commit}\"" : "null") buildConfigField('boolean', 'CLEAN_BUILD', "${proj_clean}") diff --git a/gradle.properties b/gradle.properties index b65028a..01d5e1a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,10 +2,10 @@ MORNY_ARCHIVE_NAME = morny-coeur -VERSION = 1.0.0-alpha2 +VERSION = 1.0.0-alpha3 USE_DELTA = true -VERSION_DELTA = 11061900 +VERSION_DELTA = 11061142 CODENAME = beiping diff --git a/src/main/java/cc/sukazyo/cono/morny/ServerMain.java b/src/main/java/cc/sukazyo/cono/morny/ServerMain.java index 2e330b2..6c720f8 100644 --- a/src/main/java/cc/sukazyo/cono/morny/ServerMain.java +++ b/src/main/java/cc/sukazyo/cono/morny/ServerMain.java @@ -192,8 +192,8 @@ public class ServerMain { %s [UTC]""", MornySystem.VERSION, MornySystem.CODENAME.toUpperCase(), MornySystem.getJarMd5(), - BuildConfig.COMPILE_TIMESTAMP, - CommonFormat.formatDate(BuildConfig.COMPILE_TIMESTAMP, 0) + BuildConfig.CODE_TIMESTAMP, + CommonFormat.formatDate(BuildConfig.CODE_TIMESTAMP, 0) )); return; @@ -207,7 +207,7 @@ public class ServerMain { - version %s (%s)(%d) - Morny %s""", MornySystem.VERSION, - MornySystem.getJarMd5(), BuildConfig.COMPILE_TIMESTAMP, + MornySystem.getJarMd5(), BuildConfig.CODE_TIMESTAMP, MornySystem.CODENAME.toUpperCase() )); diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyCommands.java b/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyCommands.java index 4bbe09c..8b6f124 100644 --- a/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyCommands.java +++ b/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyCommands.java @@ -243,14 +243,14 @@ public class MornyCommands { - %s core md5_hash: - %s - compile timestamp: + coding timestamp: - %d - %s [UTC]""", escapeHtml(MornySystem.CODENAME.toUpperCase()), escapeHtml(MornySystem.VERSION), escapeHtml(MornySystem.getJarMd5()), - BuildConfig.COMPILE_TIMESTAMP, - escapeHtml(formatDate(BuildConfig.COMPILE_TIMESTAMP, 0)) + BuildConfig.CODE_TIMESTAMP, + escapeHtml(formatDate(BuildConfig.CODE_TIMESTAMP, 0)) ) ).replyToMessageId(event.message().messageId()).parseMode(ParseMode.HTML)); } @@ -310,8 +310,8 @@ public class MornyCommands { escapeHtml(MornySystem.VERSION), escapeHtml(MornySystem.CODENAME), escapeHtml(MornySystem.getJarMd5()), - escapeHtml(formatDate(BuildConfig.COMPILE_TIMESTAMP, 0)), - BuildConfig.COMPILE_TIMESTAMP, + escapeHtml(formatDate(BuildConfig.CODE_TIMESTAMP, 0)), + BuildConfig.CODE_TIMESTAMP, // continuous escapeHtml(formatDuration(System.currentTimeMillis() - MornyCoeur.coeurStartTimestamp)), System.currentTimeMillis() - MornyCoeur.coeurStartTimestamp, From f362d08f3459e4f74b6b05f3b4170f73edea0762 Mon Sep 17 00:00:00 2001 From: Eyre_S Date: Mon, 7 Nov 2022 12:54:01 +0800 Subject: [PATCH 05/14] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E4=BA=86=E6=89=93?= =?UTF-8?q?=E5=8C=85=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 设置了全局 archivesBaseName - 对一些属性的声明方式进行了调整 - 为 maven publish 添加了动态配置,以在没有配置 publish url 的机器上也能够正常运行基础功能 - gradle plugin: shadow: 7.1.0 -> 7.1.2 - gradle wrapper: 7.3 -> 7.5.1 - 稍微修改了 git 状态的 log 输出方式 --- build.gradle | 60 ++++++++++++++---------- gradle.properties | 4 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 3 files changed, 39 insertions(+), 27 deletions(-) diff --git a/build.gradle b/build.gradle index c951ab2..35b05c0 100644 --- a/build.gradle +++ b/build.gradle @@ -6,9 +6,9 @@ import java.nio.charset.StandardCharsets plugins { id 'java' id 'java-library' - id 'maven-publish' id 'application' - id 'com.github.johnrengelman.shadow' version '7.1.0' + id 'maven-publish' + id 'com.github.johnrengelman.shadow' version '7.1.2' id 'com.github.gmazzo.buildconfig' version '3.1.0' id 'org.ajoberstar.grgit' version '5.0.0' } @@ -22,13 +22,13 @@ else if (isCleanBuild()) { print "git: clean build at ${grgit.head().id}" } else { final Status status = grgit.status() - println "git: non-clean-build" + print "git: non-clean-build" if (!status.unstaged.allChanges.empty) { - println "git: unstaged changes" + print "\ngit: unstaged changes" listChanges(status.unstaged) } if (!status.staged.allChanges.empty) { - println "[MornyBuild] git: staged changes" + print "\ngit: staged changes" listChanges(status.staged) } } @@ -36,6 +36,7 @@ else if (isCleanBuild()) { final String proj_group = 'cc.sukazyo' final String proj_package = "${proj_group}.cono.morny" final String proj_archive_name = MORNY_ARCHIVE_NAME +final String proj_application_main = "${proj_package}.ServerMain" final String proj_version_base = VERSION final String proj_version_delta = VERSION_DELTA @@ -49,11 +50,20 @@ 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 +String publish_local_url = null +String publish_remote_url = null +String publish_remote_username = null +String publish_remote_password = null +if (project.hasProperty("publishLocalArchiveRepoUrl")) publish_local_url = publishLocalArchiveRepoUrl +if (project.hasProperty("publishMvnRepoUrl")) { + publish_remote_url = publishMvnRepoUrl + publish_remote_username = publishMvnRepoUsername + publish_remote_password = publishMvnRepoPassword +} + group proj_group version proj_version -project.ext.archiveBaseName = proj_archive_name -project.ext.artifactId = proj_archive_name -mainClassName = "${proj_package}.ServerMain" +setArchivesBaseName proj_archive_name repositories { mavenCentral() @@ -74,6 +84,10 @@ dependencies { } +application { + mainClass = proj_application_main +} + test { useJUnitPlatform() } @@ -115,9 +129,7 @@ buildConfig { } shadowJar { - archiveBaseName.set("${project.ext.archiveBaseName}") - archiveVersion.set("${project.version}") - archiveClassifier.set("fat") + archiveClassifier.set "fat" } @SuppressWarnings("all") @@ -134,34 +146,34 @@ boolean isCleanBuild () { void listChanges (Status.Changes listing) { for (String file in listing.added) - println " add: ${file}" + print "\n add: ${file}" for (String file in listing.modified) - println " mod: ${file}" + print "\n mod: ${file}" for (String file in listing.removed) - println " del: ${file}" + print "\n del: ${file}" } publishing { repositories{ - maven { - name 'builds' - url publishLocalArchiveRepoUrl + if (publish_local_url != null) maven { + name 'archives' + url publish_local_url } - maven { + if (publish_remote_url != null) maven { name '-ws-' - url publishMvnRepoUrl + url publish_remote_url credentials { - username publishMvnRepoUsername - password publishMvnRepoPassword + username publish_remote_username + password publish_remote_password } } } publications { main (MavenPublication) { from components.java - groupId = project.group - artifactId = project.ext.artifactId - version = project.version + groupId = proj_group + artifactId = proj_archive_name + version = proj_version } } } diff --git a/gradle.properties b/gradle.properties index 01d5e1a..3db275d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,8 +4,8 @@ MORNY_ARCHIVE_NAME = morny-coeur VERSION = 1.0.0-alpha3 -USE_DELTA = true -VERSION_DELTA = 11061142 +USE_DELTA = false +VERSION_DELTA = CODENAME = beiping diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e750102..ae04661 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-7.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From d8eb37206324da9f299c99c3ff05532cb9fabaeb Mon Sep 17 00:00:00 2001 From: Eyre_S Date: Tue, 8 Nov 2022 22:37:46 +0800 Subject: [PATCH 06/14] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=9E=84=E5=BB=BA?= =?UTF-8?q?=E8=84=9A=E6=9C=AC=E4=B8=AD=20version=20delta=20=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E5=88=A4=E6=96=AD=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 现在如果 use_delta 为 false 则输出 BuildConfig.VERSION_DELTA 为 null --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 35b05c0..60a856a 100644 --- a/build.gradle +++ b/build.gradle @@ -40,7 +40,7 @@ final String proj_application_main = "${proj_package}.ServerMain" final String proj_version_base = VERSION final String proj_version_delta = VERSION_DELTA -final String proj_version_use_delta = Boolean.parseBoolean(VERSION_DELTA) +final boolean proj_version_use_delta = Boolean.parseBoolean(USE_DELTA) String proj_version = proj_version_base if (proj_version_use_delta) proj_version += "-δ${proj_version_delta}" if (proj_git) proj_version += "+git.${proj_commit.substring(0, 8)}" + (proj_clean?"":".δ") @@ -120,7 +120,7 @@ buildConfig { packageName(proj_package) buildConfigField('String', 'VERSION', "\"${proj_version}\"") - buildConfigField('String', 'VERSION_DELTA', "\"${proj_version_delta}\"") + buildConfigField('String', 'VERSION_DELTA', proj_version_use_delta ? "\"${proj_version_delta}\"" : "null") buildConfigField('String', 'CODENAME', "\"${proj_version_codename}\"") buildConfigField('long', 'CODE_TIMESTAMP', "${proj_code_time}L") buildConfigField('String', 'COMMIT', proj_git ? "\"${proj_commit}\"" : "null") From 201c8bcd1a2fd48d0379abba95de5227c8df9e95 Mon Sep 17 00:00:00 2001 From: Eyre_S Date: Wed, 9 Nov 2022 01:41:01 +0800 Subject: [PATCH 07/14] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=A1=B9=E7=9B=AE=20gi?= =?UTF-8?q?t=20=E9=93=BE=E6=8E=A5=E7=9B=B8=E5=85=B3=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=EF=BC=8C=E5=A4=A7=E6=94=B9=E5=8A=A8=E7=89=88=E6=9C=AC=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E6=96=B9=E5=BC=8F=EF=BC=8C/version=20=E4=B8=8E=20/run?= =?UTF-8?q?time=20=E5=90=88=E5=B9=B6=E8=BF=9B=20/info?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将 /version 和 /runtime 合并为了 /info 的子命令 - 旧的 /version 和 /runtime 命令仍然可用 - runtime 现在是 /info 的无参数行为 - 更新了各种位置的版本显示方式 - /version 现在通过组装的方式显示版本号的 BASE 与 DELTA 部分,并支持了可能的 git commit 显示,同时支持输出 commit 链接 - /runtime 现在通过组装的方式显示版本号的 BASE, DELTA, GIT 部分,其中也支持了 git commit 链接,同时 CODENAME 的显示方式规范为了 `version*CODENAME` 的格式 - ServerMain 的 -v 修改了显示格式,同时添加了 gitstat 字段显示 build 时的 git 信息 - ServerMain 的启动版本回显(仍使用完全体VERSION)将 md5hash 和 code-time 移到了新行 - dependencies update - java-telegram-bot-api: 5.6.0 -> 6.2.0 --- build.gradle | 5 + gradle.properties | 7 +- .../cc/sukazyo/cono/morny/MornySystem.java | 87 ++++++++++++++-- .../cc/sukazyo/cono/morny/ServerMain.java | 23 +++-- .../cono/morny/bot/command/MornyCommands.java | 42 ++++---- .../morny/bot/command/MornyInformations.java | 98 +++++++++++++++---- .../cono/morny/bot/event/OnCallMsgSend.java | 2 +- .../cono/morny/data/TelegramStickers.java | 23 ++++- .../cono/morny/util/BuildConfigField.java | 14 +++ 9 files changed, 249 insertions(+), 52 deletions(-) create mode 100644 src/main/java/cc/sukazyo/cono/morny/util/BuildConfigField.java diff --git a/build.gradle b/build.gradle index 60a856a..21ab1a4 100644 --- a/build.gradle +++ b/build.gradle @@ -14,7 +14,9 @@ plugins { } final boolean proj_git = grgit!=null +final String proj_store = MORNY_CODE_STORE final String proj_commit = proj_git ? grgit.head().id : null +final String proj_commit_path = MORNY_COMMIT_PATH final boolean proj_clean = isCleanBuild() if (!proj_git) print "[MornyBuild] git repository not available for current working space! git version tag will be disabled." @@ -120,11 +122,14 @@ buildConfig { packageName(proj_package) buildConfigField('String', 'VERSION', "\"${proj_version}\"") + buildConfigField('String', 'VERSION_BASE', "\"${proj_version_base}\"") buildConfigField('String', 'VERSION_DELTA', proj_version_use_delta ? "\"${proj_version_delta}\"" : "null") buildConfigField('String', 'CODENAME', "\"${proj_version_codename}\"") buildConfigField('long', 'CODE_TIMESTAMP', "${proj_code_time}L") buildConfigField('String', 'COMMIT', proj_git ? "\"${proj_commit}\"" : "null") buildConfigField('boolean', 'CLEAN_BUILD', "${proj_clean}") + buildConfigField('String', 'CODE_STORE', proj_store==""?"null":"\"${proj_store}\"") + buildConfigField('String', 'COMMIT_PATH', proj_commit_path==""?"null":"\"${proj_commit_path}\"") } diff --git a/gradle.properties b/gradle.properties index 3db275d..ec523fe 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,10 @@ MORNY_ARCHIVE_NAME = morny-coeur -VERSION = 1.0.0-alpha3 +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-alpha4 USE_DELTA = false VERSION_DELTA = @@ -15,6 +18,6 @@ libSpotbugsVersion = 4.7.3 libMessivaVersion = 0.1.0.1 -libJavaTelegramBotApiVersion = 5.6.0 +libJavaTelegramBotApiVersion = 6.2.0 libJunitVersion = 5.9.0 diff --git a/src/main/java/cc/sukazyo/cono/morny/MornySystem.java b/src/main/java/cc/sukazyo/cono/morny/MornySystem.java index a62290e..e15a81e 100644 --- a/src/main/java/cc/sukazyo/cono/morny/MornySystem.java +++ b/src/main/java/cc/sukazyo/cono/morny/MornySystem.java @@ -1,8 +1,10 @@ package cc.sukazyo.cono.morny; +import cc.sukazyo.cono.morny.util.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; @@ -13,20 +15,93 @@ import java.security.NoSuchAlgorithmException; public class MornySystem { /** - * 程序的语义化版本号
      - * 会由 gradle 任务 {@code updateVersionCode} 更新 + * 程序的语义化版本号. + *

      + * 这个版本号是完整(verbose)构建的——它包含了以下的 {@link #VERSION_BASE}, {@link #VERSION_DELTA}, + * 和简写的 {@link BuildConfig#COMMIT} 字段. + * @since 1.0.0-alpha4 */ - public static final String VERSION = BuildConfig.VERSION; + @BuildConfigField @Nonnull public static final String VERSION = BuildConfig.VERSION; + /** + * 程序的基础版本号. + *

      + * 它只包含了版本号中的主要信息:例如 {@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} 之后. + *

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

      * 一个单个单词,一般作为一个大版本的名称,只在重大更新改变
      * 格式保持为仅由小写字母和数字组成
      * 有时也可能是复合词或特殊的词句
      *
      - * 会由 gradle 任务 {@code updateVersionCode} 更新 */ - public static final String CODENAME = BuildConfig.CODENAME; + @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 值
      diff --git a/src/main/java/cc/sukazyo/cono/morny/ServerMain.java b/src/main/java/cc/sukazyo/cono/morny/ServerMain.java index 6c720f8..d7c4b3a 100644 --- a/src/main/java/cc/sukazyo/cono/morny/ServerMain.java +++ b/src/main/java/cc/sukazyo/cono/morny/ServerMain.java @@ -184,14 +184,24 @@ public class ServerMain { logger.info(String.format(""" Morny Cono Version - version : - %s %s + Morny %s + %s%s - md5hash : %s + - gitstat : + %s - co.time : %d %s [UTC]""", - MornySystem.VERSION, MornySystem.CODENAME.toUpperCase(), + 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) )); @@ -204,11 +214,12 @@ public class ServerMain { logger.info(String.format(""" ServerMain.java Loaded >>> - - version %s (%s)(%d) - - Morny %s""", + - version %s + - Morny %s + - <%s> [%d]""", MornySystem.VERSION, - MornySystem.getJarMd5(), BuildConfig.CODE_TIMESTAMP, - MornySystem.CODENAME.toUpperCase() + MornySystem.CODENAME.toUpperCase(), + MornySystem.getJarMd5(), BuildConfig.CODE_TIMESTAMP )); //# diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyCommands.java b/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyCommands.java index 8b6f124..f5401fc 100644 --- a/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyCommands.java +++ b/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyCommands.java @@ -21,10 +21,7 @@ import javax.annotation.Nullable; import java.net.InetAddress; import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import static cc.sukazyo.cono.morny.Log.logger; import static cc.sukazyo.cono.morny.util.CommonFormat.formatDate; @@ -226,28 +223,33 @@ public class MornyCommands { } } - private static class Version implements ITelegramCommand { + private static class Version implements ISimpleCommand { @Nonnull @Override public String getName () { return "version"; } @Nullable @Override public String[] getAliases () { return null; } - @Nonnull @Override public String getParamRule () { return ""; } - @Nonnull @Override public String getDescription () { return "检查 Bot 版本信息"; } + @Nonnull @Deprecated public String getParamRule () { return ""; } + @Nonnull @Deprecated public String getDescription () { return "检查 Bot 版本信息"; } @Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { onCommandVersionExec(event); } } - private static void onCommandVersionExec (@Nonnull Update event) { + public static void onCommandVersionExec (@Nonnull Update event) { MornyCoeur.extra().exec(new SendMessage( event.message().chat().id(), String.format( """ version: - Morny %s - - %s + - %s%s%s core md5_hash: - %s coding timestamp: - %d - %s [UTC]""", escapeHtml(MornySystem.CODENAME.toUpperCase()), - escapeHtml(MornySystem.VERSION), + escapeHtml(MornySystem.VERSION_BASE), + MornySystem.isUseDelta() ? String.format("-δ%s", escapeHtml(Objects.requireNonNull(MornySystem.VERSION_DELTA))) : "", + MornySystem.isGitBuild()?"\n- git "+ (MornySystem.currentCodePath()==null ? + String.format("%s", BuildConfig.COMMIT.substring(0, 8)) : + String.format("%s", MornySystem.currentCodePath(), BuildConfig.COMMIT.substring(0, 8)) + ) + (MornySystem.isCleanBuild() ? "" : ".δ") : "", escapeHtml(MornySystem.getJarMd5()), BuildConfig.CODE_TIMESTAMP, escapeHtml(formatDate(BuildConfig.CODE_TIMESTAMP, 0)) @@ -255,17 +257,17 @@ public class MornyCommands { ).replyToMessageId(event.message().messageId()).parseMode(ParseMode.HTML)); } - private static class MornyRuntime implements ITelegramCommand { + private static class MornyRuntime implements ISimpleCommand { @Nonnull @Override public String getName () { return "runtime"; } @Nullable @Override public String[] getAliases () { return null; } - @Nonnull @Override public String getParamRule () { return ""; } - @Nonnull @Override public String getDescription () { return "获取 Bot 运行时信息(包括版本号)"; } + @Nonnull @Deprecated public String getParamRule () { return ""; } + @Nonnull @Deprecated public String getDescription () { return "获取 Bot 运行时信息(包括版本号)"; } @Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { onCommandRuntimeExec(event); } } /** * @since 0.4.1.2 */ - private static void onCommandRuntimeExec (@Nonnull Update event) { + public static void onCommandRuntimeExec (@Nonnull Update event) { String hostname; try { hostname = InetAddress.getLocalHost().getHostName(); @@ -286,7 +288,7 @@ public class MornyCommands { - %d / %d MB - %d cores coeur version: - - %s (%s) + - %s%s%s*%s - %s - %s [UTC] - [%d] @@ -307,8 +309,14 @@ public class MornyCommands { Runtime.getRuntime().maxMemory() / 1024 / 1024, Runtime.getRuntime().availableProcessors(), // version - escapeHtml(MornySystem.VERSION), - escapeHtml(MornySystem.CODENAME), + escapeHtml(MornySystem.VERSION_BASE), + MornySystem.isUseDelta() ? String.format("-δ%s", escapeHtml(Objects.requireNonNull(MornySystem.VERSION_DELTA))) : "", + MornySystem.isGitBuild()?String.format("-git.%s%s", MornySystem.currentCodePath()==null ? ( + String.format("%s", BuildConfig.COMMIT.substring(0, 8)) + ) : ( + String.format("%s", MornySystem.currentCodePath(), BuildConfig.COMMIT.substring(0, 8)) + ), MornySystem.isCleanBuild()?"":".δ"):"", + escapeHtml(MornySystem.CODENAME.toUpperCase()), escapeHtml(MornySystem.getJarMd5()), escapeHtml(formatDate(BuildConfig.CODE_TIMESTAMP, 0)), BuildConfig.CODE_TIMESTAMP, diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyInformations.java b/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyInformations.java index 9d815bb..271f644 100644 --- a/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyInformations.java +++ b/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyInformations.java @@ -2,6 +2,7 @@ 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.ExtraAction; import cc.sukazyo.cono.morny.util.tgapi.InputCommand; import com.pengrad.telegrambot.model.Update; import com.pengrad.telegrambot.request.SendSticker; @@ -11,36 +12,97 @@ import javax.annotation.Nullable; public class MornyInformations implements ITelegramCommand { - private static final String ACT_STICKER = "stickers"; + 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 "[(stickers)|(stickers.)sticker_id]"; } - @Nonnull @Override public String getDescription () { return "输出 Morny 当前版本的一些预定义信息"; } + @Nonnull @Override public String getParamRule () { return "[subcommand]"; } + @Nonnull @Override public String getDescription () { return "输出当前 Morny 的各种信息"; } @Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { - if (!command.hasArgs() || command.getArgs().length > 1) { - MornyCoeur.extra().exec(new SendSticker(event.message().chat().id(), TelegramStickers.ID_404).replyToMessageId(event.message().messageId())); - } + if (!command.hasArgs()) echoRuntime(command, event); final String action = command.getArgs()[0]; - if (action.startsWith("stickers")) { - if (action.equals("stickers")) - TelegramStickers.echoAllStickers(MornyCoeur.extra(), event.message().chat().id(), event.message().messageId()); - else { - TelegramStickers.echoStickerByID( - action.substring((ACT_STICKER+".").length()), - MornyCoeur.extra(), event.message().chat().id(), event.message().messageId() - ); - } - return; + if (action.startsWith(SUB_STICKER)) { + echoStickers(command, event); + } else if (action.equals(SUB_RUNTIME)) { + echoRuntime(command, event); + } else if (action.equals(SUB_VERSION) || action.equals(SUB_VERSION_2)) { + echoVersion(command, event); + } else { + echo404(event); } - MornyCoeur.extra().exec(new SendSticker(event.message().chat().id(), TelegramStickers.ID_404).replyToMessageId(event.message().messageId())); - + } + + /** + * /info 子命令 {@value #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,特殊值跟随上游逻辑 + * @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 ("".equals(id)) TelegramStickers.echoAllStickers(MornyCoeur.extra(), chatId, messageId); + else TelegramStickers.echoStickerByID(id, MornyCoeur.extra(), chatId, messageId); + } + + /** + * /info 子命令 {@value #SUB_RUNTIME} + * @since 1.0.0-alpha4 + */ + public static void echoRuntime (@Nonnull InputCommand command, @Nonnull Update event) { + if (command.getArgs().length == 1) + MornyCommands.onCommandRuntimeExec(event); + else echo404(event); + } + + /** + * /info 子命令 {@value #SUB_VERSION} + * @since 1.0.0-alpha4 + */ + public static void echoVersion (@Nonnull InputCommand command, @Nonnull Update event) { + if (command.getArgs().length == 1) + MornyCommands.onCommandVersionExec(event); + else echo404(event); + } + + private static void echo404 (@Nonnull Update event) { + MornyCoeur.extra().exec(new SendSticker( + event.message().chat().id(), + TelegramStickers.ID_404 + ).replyToMessageId(event.message().messageId())); } } diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/event/OnCallMsgSend.java b/src/main/java/cc/sukazyo/cono/morny/bot/event/OnCallMsgSend.java index d02beae..0b362f9 100644 --- a/src/main/java/cc/sukazyo/cono/morny/bot/event/OnCallMsgSend.java +++ b/src/main/java/cc/sukazyo/cono/morny/bot/event/OnCallMsgSend.java @@ -37,7 +37,7 @@ public class OnCallMsgSend extends EventListener { ) { } @Override - public boolean onMessage(Update update) { + public boolean onMessage(@Nonnull Update update) { // 执行体检查 if (update.message().chat().type() != Chat.Type.Private) return false; diff --git a/src/main/java/cc/sukazyo/cono/morny/data/TelegramStickers.java b/src/main/java/cc/sukazyo/cono/morny/data/TelegramStickers.java index fb3f01c..d23d1fe 100644 --- a/src/main/java/cc/sukazyo/cono/morny/data/TelegramStickers.java +++ b/src/main/java/cc/sukazyo/cono/morny/data/TelegramStickers.java @@ -5,6 +5,7 @@ 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; /** @@ -24,7 +25,14 @@ public class TelegramStickers { public static final String ID_PROGYNOVA = "CAACAgUAAxkBAAICm2KEuL7UQqNP7vSPCg2DHJIND6UsAAKLAwACH4WSBszIo722aQ3jJAQ"; public static final String ID_NETWORK_ERR = "CAACAgEAAxkBAAID0WNJgNEkD726KW4vZeFlw0FlVVyNAAIXJgACePzGBb50o7O1RbxoKgQ"; - public static void echoAllStickers (ExtraAction actionObject, long sentChat, int replyToMessageId) { + /** + * 向 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_")) { @@ -45,7 +53,18 @@ public class TelegramStickers { } - public static void echoStickerByID (String stickerFieldID, ExtraAction actionObject, long sentChat, int replyToMessageId) { + /** + * 向 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); diff --git a/src/main/java/cc/sukazyo/cono/morny/util/BuildConfigField.java b/src/main/java/cc/sukazyo/cono/morny/util/BuildConfigField.java new file mode 100644 index 0000000..c584a8b --- /dev/null +++ b/src/main/java/cc/sukazyo/cono/morny/util/BuildConfigField.java @@ -0,0 +1,14 @@ +package cc.sukazyo.cono.morny.util; + + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; + +/** + * 这个注解表示当前字段是由 gradle 任务 {@code generateBuildConfig} 自动生成的. + * @since 1.0.0-alpha4 + */ +@Documented +@Target({ElementType.FIELD, ElementType.METHOD}) +public @interface BuildConfigField {} From 48a8fd9daa61ac75a4bf50247fdbbbb7ca28b0c3 Mon Sep 17 00:00:00 2001 From: Eyre_S Date: Wed, 9 Nov 2022 01:48:03 +0800 Subject: [PATCH 08/14] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20/info=20=E6=97=A0?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E7=9A=84=E9=94=99=E8=AF=AF=E5=8F=8D=E5=BA=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 2 +- .../cc/sukazyo/cono/morny/bot/command/MornyInformations.java | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/gradle.properties b/gradle.properties index ec523fe..c8939ed 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-alpha4 +VERSION = 1.0.0-alpha4.1 USE_DELTA = false VERSION_DELTA = diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyInformations.java b/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyInformations.java index 271f644..5558f6e 100644 --- a/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyInformations.java +++ b/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyInformations.java @@ -25,7 +25,10 @@ public class MornyInformations implements ITelegramCommand { @Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { - if (!command.hasArgs()) echoRuntime(command, event); + if (!command.hasArgs()) { + MornyCommands.onCommandRuntimeExec(event); + return; + } final String action = command.getArgs()[0]; From 837ec178d358e70838a5e916461ec37a1862566a Mon Sep 17 00:00:00 2001 From: Eyre_S Date: Wed, 9 Nov 2022 12:03:17 +0800 Subject: [PATCH 09/14] =?UTF-8?q?=E5=B0=86=E5=B8=A6=E6=9C=89=20git=20?= =?UTF-8?q?=E7=9A=84=20version=20=E6=9B=B4=E5=90=8D=E4=B8=BA=20version-ful?= =?UTF-8?q?l=EF=BC=8C=E5=8E=9F=E5=85=88=E7=9A=84=20version=20=E5=8E=BB?= =?UTF-8?q?=E9=99=A4=20git=20=E7=AD=89=E9=99=84=E5=8A=A0=E5=B1=9E=E6=80=A7?= =?UTF-8?q?=EF=BC=8C=E4=BD=9C=E4=B8=BA=20maven=20=E5=8C=85=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E4=BD=BF=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 8 ++++---- gradle.properties | 2 +- .../cc/sukazyo/cono/morny/MornySystem.java | 19 +++++++++++++++++-- .../cc/sukazyo/cono/morny/ServerMain.java | 2 +- .../java/cc/sukazyo/cono/morny/MornyCLI.java | 2 +- 5 files changed, 24 insertions(+), 9 deletions(-) diff --git a/build.gradle b/build.gradle index 21ab1a4..1629e2c 100644 --- a/build.gradle +++ b/build.gradle @@ -43,9 +43,8 @@ final String proj_application_main = "${proj_package}.ServerMain" final String proj_version_base = VERSION final String proj_version_delta = VERSION_DELTA final boolean proj_version_use_delta = Boolean.parseBoolean(USE_DELTA) -String proj_version = proj_version_base -if (proj_version_use_delta) proj_version += "-δ${proj_version_delta}" -if (proj_git) proj_version += "+git.${proj_commit.substring(0, 8)}" + (proj_clean?"":".δ") +final String proj_version = proj_version_base + (proj_version_use_delta ? "-δ${proj_version_delta}" : "") +final String proj_version_full = proj_version + (proj_git ? "+git.${proj_commit.substring(0, 8)}" + (proj_clean?"":".δ") : "") final String proj_version_codename = CODENAME final long proj_code_time = proj_clean ? grgit.head().dateTime.toInstant().toEpochMilli() : System.currentTimeMillis() @@ -64,7 +63,7 @@ if (project.hasProperty("publishMvnRepoUrl")) { } group proj_group -version proj_version +version proj_version_full setArchivesBaseName proj_archive_name repositories { @@ -122,6 +121,7 @@ buildConfig { packageName(proj_package) buildConfigField('String', 'VERSION', "\"${proj_version}\"") + buildConfigField('String', 'VERSION_FULL', "\"${proj_version_full}\"") buildConfigField('String', 'VERSION_BASE', "\"${proj_version_base}\"") buildConfigField('String', 'VERSION_DELTA', proj_version_use_delta ? "\"${proj_version_delta}\"" : "null") buildConfigField('String', 'CODENAME', "\"${proj_version_codename}\"") diff --git a/gradle.properties b/gradle.properties index c8939ed..cdee59b 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-alpha4.1 +VERSION = 1.0.0-alpha4.2 USE_DELTA = false VERSION_DELTA = diff --git a/src/main/java/cc/sukazyo/cono/morny/MornySystem.java b/src/main/java/cc/sukazyo/cono/morny/MornySystem.java index e15a81e..c00fc86 100644 --- a/src/main/java/cc/sukazyo/cono/morny/MornySystem.java +++ b/src/main/java/cc/sukazyo/cono/morny/MornySystem.java @@ -17,11 +17,23 @@ public class MornySystem { /** * 程序的语义化版本号. *

      - * 这个版本号是完整(verbose)构建的——它包含了以下的 {@link #VERSION_BASE}, {@link #VERSION_DELTA}, - * 和简写的 {@link BuildConfig#COMMIT} 字段. + * 这个版本号包含了以下的 {@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; /** * 程序的基础版本号. *

      @@ -37,6 +49,9 @@ public class MornySystem { * {@link null} 作为值,表示这个字段没有被使用. *

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

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

      * 目前并不多被使用. * @since 1.0.0-alpha4 diff --git a/src/main/java/cc/sukazyo/cono/morny/ServerMain.java b/src/main/java/cc/sukazyo/cono/morny/ServerMain.java index d7c4b3a..d07d498 100644 --- a/src/main/java/cc/sukazyo/cono/morny/ServerMain.java +++ b/src/main/java/cc/sukazyo/cono/morny/ServerMain.java @@ -217,7 +217,7 @@ public class ServerMain { - version %s - Morny %s - <%s> [%d]""", - MornySystem.VERSION, + MornySystem.VERSION_FULL, MornySystem.CODENAME.toUpperCase(), MornySystem.getJarMd5(), BuildConfig.CODE_TIMESTAMP )); diff --git a/src/test/java/cc/sukazyo/cono/morny/MornyCLI.java b/src/test/java/cc/sukazyo/cono/morny/MornyCLI.java index c26fca6..ef788b2 100644 --- a/src/test/java/cc/sukazyo/cono/morny/MornyCLI.java +++ b/src/test/java/cc/sukazyo/cono/morny/MornyCLI.java @@ -9,7 +9,7 @@ public class MornyCLI { public static void main (String[] args) { Scanner line = new Scanner(System.in); - System.out.print("$ java -jar morny-coeur-"+BuildConfig.VERSION+".jar " ); + System.out.print("$ java -jar morny-coeur-"+MornySystem.VERSION_FULL+".jar " ); String x = line.nextLine(); ServerMain.main(UniversalCommand.format(x)); From 618d77746305c19d2d69f6c9644f933a03f6bfaa Mon Sep 17 00:00:00 2001 From: Eyre_S Date: Wed, 9 Nov 2022 14:03:53 +0800 Subject: [PATCH 10/14] fix gradlew exec perm --- gradlew | 0 gradlew.bat | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 gradlew mode change 100644 => 100755 gradlew.bat diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 diff --git a/gradlew.bat b/gradlew.bat old mode 100644 new mode 100755 From 01b4eea917c7c2caa6505fe700549bc4ff52994b Mon Sep 17 00:00:00 2001 From: Eyre_S Date: Thu, 10 Nov 2022 23:06:52 +0800 Subject: [PATCH 11/14] =?UTF-8?q?=E4=B8=BAerror=E5=92=8Cexit/save=20403=20?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E4=BA=86=20Morny=20Report=EF=BC=8CtrustedCha?= =?UTF-8?q?t=3D=20-1=EF=BC=8Ctypo=20=E4=BB=A5=E5=8F=8A=E6=96=87=E6=A1=88?= =?UTF-8?q?=20fix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 优化了 coeur 中 exception 的 stackTrace 的输出方式 - 大幅度修改了 EventListenerManager 中报错的逻辑使其更加正常了许多 - 添加了 reportToChat 以及 --report-to 选项用在 MornyReport 中 - 为 coeur 中的错误报告添加了 MornyReport.exception - 为 save/exit 两个需要权限的命令添加了 MornyReport.unauthenticatedAction - 添加了一个方法可以检查 coeur(telegram_bot) 是否已完成初始化以存取 coeur 的内容 --- gradle.properties | 2 +- src/main/java/cc/sukazyo/cono/morny/Log.java | 9 +++ .../cc/sukazyo/cono/morny/MornyCoeur.java | 10 ++- .../cc/sukazyo/cono/morny/MornyConfig.java | 16 +++++ .../cc/sukazyo/cono/morny/MornySystem.java | 4 +- .../cc/sukazyo/cono/morny/MornyTrusted.java | 1 + .../cc/sukazyo/cono/morny/ServerMain.java | 7 ++ .../morny/bot/api/EventListenerManager.java | 33 ++++----- .../cono/morny/bot/command/Encryptor.java | 3 + .../cono/morny/bot/command/MornyCommands.java | 3 + .../cono/morny/bot/command/Testing.java | 2 +- .../cono/morny/bot/command/私わね.java | 13 ++-- .../cono/morny/daemon/MedicationTimer.java | 4 +- .../cono/morny/daemon/MornyReport.java | 67 +++++++++++++++++++ .../cono/morny/daemon/TrackerDataManager.java | 7 +- 15 files changed, 149 insertions(+), 32 deletions(-) create mode 100644 src/main/java/cc/sukazyo/cono/morny/daemon/MornyReport.java diff --git a/gradle.properties b/gradle.properties index cdee59b..9d43267 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-alpha4.2 +VERSION = 1.0.0-alpha5 USE_DELTA = false VERSION_DELTA = diff --git a/src/main/java/cc/sukazyo/cono/morny/Log.java b/src/main/java/cc/sukazyo/cono/morny/Log.java index b58c825..f4d1ea4 100644 --- a/src/main/java/cc/sukazyo/cono/morny/Log.java +++ b/src/main/java/cc/sukazyo/cono/morny/Log.java @@ -3,6 +3,9 @@ package cc.sukazyo.cono.morny; import cc.sukazyo.messiva.Logger; import cc.sukazyo.messiva.appender.ConsoleAppender; +import java.io.PrintWriter; +import java.io.StringWriter; + /** * Morny 的 log 管理器 */ @@ -15,4 +18,10 @@ public class Log { */ public static final Logger logger = new Logger(new ConsoleAppender()); + public static String exceptionLog (Exception e) { + final StringWriter stackTrace = new StringWriter(); + e.printStackTrace(new PrintWriter(stackTrace)); + return stackTrace.toString(); + } + } diff --git a/src/main/java/cc/sukazyo/cono/morny/MornyCoeur.java b/src/main/java/cc/sukazyo/cono/morny/MornyCoeur.java index 452d0e4..d887b99 100644 --- a/src/main/java/cc/sukazyo/cono/morny/MornyCoeur.java +++ b/src/main/java/cc/sukazyo/cono/morny/MornyCoeur.java @@ -223,7 +223,7 @@ public class MornyCoeur { logger.info("Succeed login to @" + remote.username()); return new LogInResult(account, remote.username(), remote.id()); } catch (Exception e) { - e.printStackTrace(System.out); + logger.error(Log.exceptionLog(e)); logger.error("login failed."); } } @@ -239,6 +239,14 @@ public class MornyCoeur { logger.info("done all save action."); } + /** + * 检查 Coeur 是否已经完成初始化. + * @since 1.0.0-alpha5 + */ + public static boolean available() { + return INSTANCE != null; + } + /** * 获取登录成功后的 telegram bot 对象 * diff --git a/src/main/java/cc/sukazyo/cono/morny/MornyConfig.java b/src/main/java/cc/sukazyo/cono/morny/MornyConfig.java index 004302c..0e02f9f 100644 --- a/src/main/java/cc/sukazyo/cono/morny/MornyConfig.java +++ b/src/main/java/cc/sukazyo/cono/morny/MornyConfig.java @@ -88,6 +88,16 @@ public class MornyConfig { public final boolean commandLoginRefresh; public final boolean commandLogoutClear; + /* ======================================= * + * system: morny report * + * ======================================= */ + + /** + * 控制 Morny Coeur 系统的报告的报告对象. + * @since 1.0.0-alpha5 + */ + public final long reportToChat; + /* ======================================= * * function: dinner query tool * * ======================================= */ @@ -95,6 +105,10 @@ public class MornyConfig { @Nonnull public final Set dinnerTrustedReaders; public final long dinnerChatId; + /* ======================================= * + * End Configs | ConfigBuilder * + * ======================================= */ + public MornyConfig (@Nonnull Prototype prototype) throws CheckFailure { this.telegramBotApiServer = prototype.telegramBotApiServer; this.telegramBotApiServer4File = prototype.telegramBotApiServer4File; @@ -110,6 +124,7 @@ public class MornyConfig { this.commandLogoutClear = prototype.commandLogoutClear; this.dinnerTrustedReaders = prototype.dinnerTrustedReaders; this.dinnerChatId = prototype.dinnerChatId; + this.reportToChat = prototype.reportToChat; } public static class CheckFailure extends Exception { @@ -131,6 +146,7 @@ public class MornyConfig { public boolean commandLogoutClear = false; @Nonnull public Set dinnerTrustedReaders = new HashSet<>(); public long dinnerChatId = -1001707106392L; + public long reportToChat = -1001650050443L; } diff --git a/src/main/java/cc/sukazyo/cono/morny/MornySystem.java b/src/main/java/cc/sukazyo/cono/morny/MornySystem.java index c00fc86..a4e2933 100644 --- a/src/main/java/cc/sukazyo/cono/morny/MornySystem.java +++ b/src/main/java/cc/sukazyo/cono/morny/MornySystem.java @@ -1,5 +1,6 @@ package cc.sukazyo.cono.morny; +import cc.sukazyo.cono.morny.daemon.MornyReport; import cc.sukazyo.cono.morny.util.BuildConfigField; import cc.sukazyo.cono.morny.util.FileUtils; @@ -135,7 +136,8 @@ public class MornySystem { } catch (IOException | URISyntaxException e) { return ""; } catch (NoSuchAlgorithmException e) { - e.printStackTrace(System.out); + Log.logger.error(Log.exceptionLog(e)); + MornyReport.exception(e, ""); return ""; } } diff --git a/src/main/java/cc/sukazyo/cono/morny/MornyTrusted.java b/src/main/java/cc/sukazyo/cono/morny/MornyTrusted.java index ae2b3bb..7a43fa0 100644 --- a/src/main/java/cc/sukazyo/cono/morny/MornyTrusted.java +++ b/src/main/java/cc/sukazyo/cono/morny/MornyTrusted.java @@ -27,6 +27,7 @@ public class MornyTrusted { */ 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); } diff --git a/src/main/java/cc/sukazyo/cono/morny/ServerMain.java b/src/main/java/cc/sukazyo/cono/morny/ServerMain.java index d07d498..6707185 100644 --- a/src/main/java/cc/sukazyo/cono/morny/ServerMain.java +++ b/src/main/java/cc/sukazyo/cono/morny/ServerMain.java @@ -49,6 +49,9 @@ public class ServerMain { * {@code --api-files} 单独设定 {@link MornyCoeur#getAccount() bot client} 使用的 telegram bot file api server * *

    • + * {@code --report-to} 设定 {@link cc.sukazyo.cono.morny.daemon.MornyReport} 的运行报告要发送到的 telegram 频道 + *
    • + *
    • * {@code --no-hello} 不在主程序启动时输出用于欢迎消息的字符画。 * 与 {@code --only-hello} 参数不兼容 —— 会导致程序完全没有任何输出 *
    • @@ -158,6 +161,10 @@ public class ServerMain { config.telegramBotApiServer4File = args[i]; continue; } + case "--report-to" -> { + config.reportToChat = Long.parseLong(args[i]); + continue; + } } } diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/api/EventListenerManager.java b/src/main/java/cc/sukazyo/cono/morny/bot/api/EventListenerManager.java index 18d0004..671dfd3 100644 --- a/src/main/java/cc/sukazyo/cono/morny/bot/api/EventListenerManager.java +++ b/src/main/java/cc/sukazyo/cono/morny/bot/api/EventListenerManager.java @@ -1,5 +1,7 @@ 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; @@ -32,27 +34,20 @@ public class EventListenerManager { if (exec.apply(x)) return; - } catch (EventRuntimeException e) { - - final StringBuilder errorMessage = new StringBuilder(); - errorMessage.append("Event runtime breaks: " + e.getMessage()).append('\n'); - errorMessage.append("at " + e.getStackTrace()[0].toString()).append('\n'); - errorMessage.append("at " + e.getStackTrace()[1].toString()).append('\n'); - errorMessage.append("at " + e.getStackTrace()[2].toString()).append('\n'); - errorMessage.append("at " + e.getStackTrace()[3].toString()).append('\n'); - if (e instanceof EventRuntimeException.ActionFailed) { - errorMessage.append(( - "\"telegram request track\": " + - new GsonBuilder().setPrettyPrinting().create().toJson(((EventRuntimeException.ActionFailed)e).getResponse()) - ).indent(4)).append('\n'); - } - - logger.error(errorMessage.toString()); - } catch (Exception e) { - logger.error("Event Error!"); - e.printStackTrace(System.out); + 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"); } } 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 index e770b9f..5ceb213 100644 --- a/src/main/java/cc/sukazyo/cono/morny/bot/command/Encryptor.java +++ b/src/main/java/cc/sukazyo/cono/morny/bot/command/Encryptor.java @@ -1,6 +1,7 @@ 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; @@ -88,6 +89,7 @@ public class Encryptor implements ITelegramCommand { )).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 @@ -110,6 +112,7 @@ public class Encryptor implements ITelegramCommand { )).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 diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyCommands.java b/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyCommands.java index f5401fc..5925046 100644 --- a/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyCommands.java +++ b/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyCommands.java @@ -3,6 +3,7 @@ package cc.sukazyo.cono.morny.bot.command; import cc.sukazyo.cono.morny.BuildConfig; import cc.sukazyo.cono.morny.MornyCoeur; import cc.sukazyo.cono.morny.MornySystem; +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; @@ -220,6 +221,7 @@ public class MornyCommands { ).replyToMessageId(event.message().messageId()) ); logger.info("403 exited tag from user " + TGToString.as(event.message().from()).toStringLogTag()); + MornyReport.unauthenticatedAction("/exit", event.message().from()); } } @@ -375,6 +377,7 @@ public class MornyCommands { ).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/java/cc/sukazyo/cono/morny/bot/command/Testing.java b/src/main/java/cc/sukazyo/cono/morny/bot/command/Testing.java index d1bfb80..8039ce7 100644 --- a/src/main/java/cc/sukazyo/cono/morny/bot/command/Testing.java +++ b/src/main/java/cc/sukazyo/cono/morny/bot/command/Testing.java @@ -28,7 +28,7 @@ public class Testing implements ISimpleCommand { MornyCoeur.extra().exec(new SendMessage( event.message().chat().id(), - "Just a TEST command." + "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 index 0c92c84..b776046 100644 --- a/src/main/java/cc/sukazyo/cono/morny/bot/command/私わね.java +++ b/src/main/java/cc/sukazyo/cono/morny/bot/command/私わね.java @@ -22,12 +22,13 @@ public class 私わね implements ISimpleCommand { public void execute (@Nonnull InputCommand command, @Nonnull Update event) { if (ThreadLocalRandom.current().nextInt(521) == 0) { // 可以接入未来的心情系统(如果有的话) - 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 = 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 diff --git a/src/main/java/cc/sukazyo/cono/morny/daemon/MedicationTimer.java b/src/main/java/cc/sukazyo/cono/morny/daemon/MedicationTimer.java index 813640b..5faba4a 100644 --- a/src/main/java/cc/sukazyo/cono/morny/daemon/MedicationTimer.java +++ b/src/main/java/cc/sukazyo/cono/morny/daemon/MedicationTimer.java @@ -12,6 +12,7 @@ import com.pengrad.telegrambot.response.SendResponse; import java.util.ArrayList; import java.util.List; +import static cc.sukazyo.cono.morny.Log.exceptionLog; import static cc.sukazyo.cono.morny.Log.logger; public class MedicationTimer extends Thread { @@ -40,7 +41,8 @@ public class MedicationTimer extends Thread { logger.info("MedicationTimer was interrupted, will be exit now"); } catch (Exception e) { logger.error("Unexpected error occurred"); - e.printStackTrace(System.out); + logger.error(exceptionLog(e)); + MornyReport.exception(e); } } logger.info("MedicationTimer stopped"); diff --git a/src/main/java/cc/sukazyo/cono/morny/daemon/MornyReport.java b/src/main/java/cc/sukazyo/cono/morny/daemon/MornyReport.java new file mode 100644 index 0000000..a6d37e2 --- /dev/null +++ b/src/main/java/cc/sukazyo/cono/morny/daemon/MornyReport.java @@ -0,0 +1,67 @@ +package cc.sukazyo.cono.morny.daemon; + +import cc.sukazyo.cono.morny.Log; +import cc.sukazyo.cono.morny.MornyCoeur; +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 static cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml; + +public class MornyReport { + + private static , R extends BaseResponse> void executeReport (@Nonnull T report) { + if (!MornyCoeur.available()) return; + try { + MornyCoeur.extra().exec(report); + } catch (EventRuntimeException.ActionFailed e) { + Log.logger.warn("cannot execute report to telegram:"); + Log.logger.warn(Log.exceptionLog(e)); + } + } + + public static void exception (@Nonnull Exception e, @Nullable String description) { + if (!MornyCoeur.available()) 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 (!MornyCoeur.available()) 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)); + } + +} diff --git a/src/main/java/cc/sukazyo/cono/morny/daemon/TrackerDataManager.java b/src/main/java/cc/sukazyo/cono/morny/daemon/TrackerDataManager.java index d0f8ab0..264a69a 100644 --- a/src/main/java/cc/sukazyo/cono/morny/daemon/TrackerDataManager.java +++ b/src/main/java/cc/sukazyo/cono/morny/daemon/TrackerDataManager.java @@ -10,6 +10,7 @@ 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 { @@ -113,8 +114,10 @@ public class TrackerDataManager { )); } catch (Exception e) { - logger.error(String.format("exception in write tracker data: %d/%d/%d", chat, user, timestamp)); - e.printStackTrace(System.out); + 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); } } From 3689962cb3fd876bcffe6f6a923ceafd2e97e646 Mon Sep 17 00:00:00 2001 From: Eyre_S Date: Fri, 11 Nov 2022 16:37:24 +0800 Subject: [PATCH 12/14] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BA=86=20morny=20log?= =?UTF-8?q?in/exit=20=E7=9A=84=E6=8A=A5=E5=91=8A=EF=BC=8C*msg=20=E7=8E=B0?= =?UTF-8?q?=E5=9C=A8=E6=94=AF=E6=8C=81=E4=BA=86=E5=8F=AA=E5=8C=85=E5=90=AB?= =?UTF-8?q?=E5=8F=91=E9=80=81=20id=20=E4=B8=8D=E5=8C=85=E5=90=AB=E5=8F=91?= =?UTF-8?q?=E9=80=81=E4=BD=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 为 MornyCoeur 添加了 whileExitReason (exit/getExitReason) 接口,用于安全退出时指定推出原因 - MornyConfig 添加了一个 Sensitive 注解用于标明字段值属于敏感字段不应该被打印 - --- gradle.properties | 2 +- .../cc/sukazyo/cono/morny/MornyCoeur.java | 12 ++- .../cc/sukazyo/cono/morny/MornyConfig.java | 11 ++- .../cono/morny/bot/command/MornyCommands.java | 2 +- .../cono/morny/bot/event/OnCallMsgSend.java | 13 +-- .../cono/morny/daemon/MornyDaemons.java | 4 + .../cono/morny/daemon/MornyReport.java | 91 ++++++++++++++++++- 7 files changed, 123 insertions(+), 12 deletions(-) diff --git a/gradle.properties b/gradle.properties index 9d43267..d8d160f 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-alpha5 +VERSION = 1.0.0-alpha6 USE_DELTA = false VERSION_DELTA = diff --git a/src/main/java/cc/sukazyo/cono/morny/MornyCoeur.java b/src/main/java/cc/sukazyo/cono/morny/MornyCoeur.java index d887b99..49f8655 100644 --- a/src/main/java/cc/sukazyo/cono/morny/MornyCoeur.java +++ b/src/main/java/cc/sukazyo/cono/morny/MornyCoeur.java @@ -60,6 +60,8 @@ public class MornyCoeur { */ public static final long coeurStartTimestamp = ServerMain.systemStartupTime; + private Object whileExitReason = null; + private record LogInResult(TelegramBot account, String username, long userid) { } /** @@ -152,7 +154,6 @@ public class MornyCoeur { * 用于退出时进行缓存的任务处理等进行安全退出 */ private void exitCleanup () { - logger.info("clean:save tracker data."); MornyDaemons.stop(); if (config.commandLogoutClear) { commandManager.automaticRemoveList(); @@ -304,4 +305,13 @@ public class MornyCoeur { 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/java/cc/sukazyo/cono/morny/MornyConfig.java b/src/main/java/cc/sukazyo/cono/morny/MornyConfig.java index 0e02f9f..be61e15 100644 --- a/src/main/java/cc/sukazyo/cono/morny/MornyConfig.java +++ b/src/main/java/cc/sukazyo/cono/morny/MornyConfig.java @@ -2,11 +2,20 @@ package cc.sukazyo.cono.morny; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import java.lang.annotation.*; import java.util.HashSet; import java.util.Set; public class MornyConfig { + /** + * 表示一个字段的值属于敏感数据,不应该被执行打印等操作。 + */ + @Retention(RetentionPolicy.RUNTIME) + @Documented + @Target({ElementType.FIELD, ElementType.METHOD}) + public @interface Sensitive {} + /* ======================================= * * Config props Names Definition * * ======================================= */ @@ -37,7 +46,7 @@ public class MornyConfig { *

      * 这个值必须设定。 */ - @Nonnull public final String telegramBotKey; + @Nonnull @Sensitive public final String telegramBotKey; /** * morny 所使用的 bot 的 username. *

      diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyCommands.java b/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyCommands.java index 5925046..9ad3087 100644 --- a/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyCommands.java +++ b/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyCommands.java @@ -213,7 +213,7 @@ public class MornyCommands { ).replyToMessageId(event.message().messageId()) ); logger.info("Morny exited by user " + TGToString.as(event.message().from()).toStringLogTag()); - System.exit(0); + MornyCoeur.exit(0, event.message().from()); } else { MornyCoeur.extra().exec(new SendSticker( event.message().chat().id(), diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/event/OnCallMsgSend.java b/src/main/java/cc/sukazyo/cono/morny/bot/event/OnCallMsgSend.java index 0b362f9..b4eaaec 100644 --- a/src/main/java/cc/sukazyo/cono/morny/bot/event/OnCallMsgSend.java +++ b/src/main/java/cc/sukazyo/cono/morny/bot/event/OnCallMsgSend.java @@ -27,12 +27,12 @@ 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 static final Pattern REGEX_MSG_SENDREQ_DATA_HEAD = Pattern.compile("^\\*msg(-?\\d+)(\\*\\S+)?(?:\\n([\\s\\S]+))?$"); private record MessageToSend ( - String message, - MessageEntity[] entities, - ParseMode parseMode, + @Nullable String message, + @Nullable MessageEntity[] entities, + @Nullable ParseMode parseMode, long targetId ) { } @@ -62,7 +62,7 @@ public class OnCallMsgSend extends EventListener { // 发送体处理 if (update.message().replyToMessage() == null) return answer404(update); msgsendReqBody = parseRequest(update.message().replyToMessage()); - if (msgsendReqBody == null) return answer404(update); + if (msgsendReqBody == null || msgsendReqBody.message == null) return answer404(update); // 执行发送任务 SendResponse sendResponse = MornyCoeur.getAccount().execute(parseMessageToSend(msgsendReqBody)); if (!sendResponse.isOk()) { // 发送失败 @@ -150,7 +150,8 @@ public class OnCallMsgSend extends EventListener { ).replyToMessageId(update.message().messageId()).parseMode(ParseMode.HTML)); } // 发送文本测试 - SendResponse testSendResp = MornyCoeur.getAccount().execute( + 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()) { diff --git a/src/main/java/cc/sukazyo/cono/morny/daemon/MornyDaemons.java b/src/main/java/cc/sukazyo/cono/morny/daemon/MornyDaemons.java index d40ba47..710a07a 100644 --- a/src/main/java/cc/sukazyo/cono/morny/daemon/MornyDaemons.java +++ b/src/main/java/cc/sukazyo/cono/morny/daemon/MornyDaemons.java @@ -1,5 +1,7 @@ package cc.sukazyo.cono.morny.daemon; +import cc.sukazyo.cono.morny.MornyCoeur; + import static cc.sukazyo.cono.morny.Log.logger; public class MornyDaemons { @@ -10,6 +12,7 @@ public class MornyDaemons { logger.info("ALL Morny Daemons starting..."); // TrackerDataManager.init(); medicationTimerInstance.start(); + MornyReport.onMornyLogIn(); logger.info("Morny Daemons started."); } @@ -23,6 +26,7 @@ public class MornyDaemons { // 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/java/cc/sukazyo/cono/morny/daemon/MornyReport.java b/src/main/java/cc/sukazyo/cono/morny/daemon/MornyReport.java index a6d37e2..c79b223 100644 --- a/src/main/java/cc/sukazyo/cono/morny/daemon/MornyReport.java +++ b/src/main/java/cc/sukazyo/cono/morny/daemon/MornyReport.java @@ -2,6 +2,7 @@ package cc.sukazyo.cono.morny.daemon; import cc.sukazyo.cono.morny.Log; import cc.sukazyo.cono.morny.MornyCoeur; +import cc.sukazyo.cono.morny.MornyConfig; import cc.sukazyo.cono.morny.util.tgapi.event.EventRuntimeException; import cc.sukazyo.cono.morny.util.tgapi.formatting.TGToString; import com.google.gson.GsonBuilder; @@ -14,6 +15,9 @@ 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 { @@ -23,8 +27,10 @@ public class MornyReport { try { MornyCoeur.extra().exec(report); } catch (EventRuntimeException.ActionFailed e) { - Log.logger.warn("cannot execute report to telegram:"); - Log.logger.warn(Log.exceptionLog(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)); } } @@ -64,4 +70,85 @@ public class MornyReport { ).parseMode(ParseMode.HTML)); } + /** + * morny 登陆时的报告发送,包含已登录的账号 id 以及启动配置。 + * @since 1.0.0-alpha6 + */ + public static void onMornyLogIn () { + executeReport(new SendMessage( + MornyCoeur.config().reportToChat, + String.format(""" + ▌Morny Logged in + as user @%s + + as config fields: + %s + """, + 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 (!MornyCoeur.available()) 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)); + } + } From fbbfe73ac12cb72807c447b85109cb438d332785 Mon Sep 17 00:00:00 2001 From: Eyre_S Date: Fri, 11 Nov 2022 18:32:04 +0800 Subject: [PATCH 13/14] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BA=86=20"meow-set"?= =?UTF-8?q?=20=E9=83=A8=E5=88=86=E7=9A=84=E6=96=87=E6=A1=88=EF=BC=8C?= =?UTF-8?q?=E5=B9=B6=E4=B8=BA=E5=85=B6=E6=B7=BB=E5=8A=A0=E4=BA=86=E7=89=B9?= =?UTF-8?q?=E5=BC=82=E5=8C=96=E5=9B=9E=E5=A4=8D=E7=9A=84=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=EF=BC=8C=E4=BF=AE=E5=A4=8D=E5=85=B6=E4=BB=A5=E5=8F=8A=20--repo?= =?UTF-8?q?rt-to=20=E7=9A=84=20bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修复了上次提交的 --report-to 参数没有被正确处理问题 - 创建了一个新的补丁事件,修复了 meow-set 无法使用的问题 --- gradle.properties | 2 +- .../cc/sukazyo/cono/morny/ServerMain.java | 1 + .../cono/morny/bot/command/MornyCommands.java | 10 +++-- .../sukazyo/cono/morny/bot/command/喵呜.java | 40 +++++++++++-------- .../cono/morny/bot/event/EventListeners.java | 2 + .../morny/bot/event/OnUniMeowTrigger.java | 36 +++++++++++++++++ 6 files changed, 71 insertions(+), 20 deletions(-) create mode 100644 src/main/java/cc/sukazyo/cono/morny/bot/event/OnUniMeowTrigger.java diff --git a/gradle.properties b/gradle.properties index d8d160f..50b2c53 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-alpha6 +VERSION = 1.0.0-beta1 USE_DELTA = false VERSION_DELTA = diff --git a/src/main/java/cc/sukazyo/cono/morny/ServerMain.java b/src/main/java/cc/sukazyo/cono/morny/ServerMain.java index 6707185..e9237ee 100644 --- a/src/main/java/cc/sukazyo/cono/morny/ServerMain.java +++ b/src/main/java/cc/sukazyo/cono/morny/ServerMain.java @@ -162,6 +162,7 @@ public class ServerMain { continue; } case "--report-to" -> { + i++; config.reportToChat = Long.parseLong(args[i]); continue; } diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyCommands.java b/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyCommands.java index 9ad3087..e50db1b 100644 --- a/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyCommands.java +++ b/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyCommands.java @@ -3,6 +3,7 @@ package cc.sukazyo.cono.morny.bot.command; import cc.sukazyo.cono.morny.BuildConfig; import cc.sukazyo.cono.morny.MornyCoeur; import cc.sukazyo.cono.morny.MornySystem; +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; @@ -83,12 +84,15 @@ public class MornyCommands { // 统一注册这些奇怪的东西&.& register( + new 私わね(), + new 喵呜.Progynova() + ); + // special: 注册出于兼容使用的特别 event 的数据 + OnUniMeowTrigger.register( new 喵呜.抱抱(), new 喵呜.揉揉(), new 喵呜.蹭蹭(), - new 喵呜.贴贴(), - new 私わね(), - new 喵呜.Progynova() + new 喵呜.贴贴() ); } diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/command/喵呜.java b/src/main/java/cc/sukazyo/cono/morny/bot/command/喵呜.java index 2bdbb7d..692ce2a 100644 --- a/src/main/java/cc/sukazyo/cono/morny/bot/command/喵呜.java +++ b/src/main/java/cc/sukazyo/cono/morny/bot/command/喵呜.java @@ -3,6 +3,7 @@ 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; @@ -11,6 +12,16 @@ 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 喵呜 { @@ -18,10 +29,7 @@ public class 喵呜 { @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) { - MornyCoeur.extra().exec(new SendMessage( - event.message().chat().id(), - "抱抱——" - )); + replyingSet(event, "抱抱", "抱抱"); } } @@ -29,10 +37,7 @@ public class 喵呜 { @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) { - MornyCoeur.extra().exec(new SendMessage( - event.message().chat().id(), - "蹭蹭w" - )); + replyingSet(event, "蹭蹭", "摸摸"); } } @@ -40,10 +45,7 @@ public class 喵呜 { @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) { - MornyCoeur.extra().exec(new SendMessage( - event.message().chat().id(), - "喵呜~-" - )); + replyingSet(event, "揉揉", "蹭蹭"); } } @@ -51,13 +53,19 @@ public class 喵呜 { @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) { - MornyCoeur.extra().exec(new SendMessage( - event.message().chat().id(), - "(贴贴喵呜&.&)" - ).parseMode(ParseMode.HTML)); + 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]; } diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/event/EventListeners.java b/src/main/java/cc/sukazyo/cono/morny/bot/event/EventListeners.java index 7b165f9..389b037 100644 --- a/src/main/java/cc/sukazyo/cono/morny/bot/event/EventListeners.java +++ b/src/main/java/cc/sukazyo/cono/morny/bot/event/EventListeners.java @@ -16,6 +16,7 @@ public class EventListeners { 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 void registerAllListeners () { EventListenerManager.addListener( @@ -24,6 +25,7 @@ public class EventListeners { /* write functional event behind here */ // KUOHUANHUAN_NEED_SLEEP, COMMANDS_LISTENER, + UNI_MEOW_TRIGGER, RANDOMLY_TRIGGERED, USER_RANDOMS, USER_SLASH_ACTION, diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/event/OnUniMeowTrigger.java b/src/main/java/cc/sukazyo/cono/morny/bot/event/OnUniMeowTrigger.java new file mode 100644 index 0000000..59e8be1 --- /dev/null +++ b/src/main/java/cc/sukazyo/cono/morny/bot/event/OnUniMeowTrigger.java @@ -0,0 +1,36 @@ +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(); + } + +} From c4a709491d2ed635d9371ae9ed09d22309c207e1 Mon Sep 17 00:00:00 2001 From: Eyre_S Date: Sat, 12 Nov 2022 13:42:23 +0800 Subject: [PATCH 14/14] =?UTF-8?q?=E4=B8=BA=20loginReport=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E4=BA=86=E7=89=88=E6=9C=AC=E5=8F=B7=EF=BC=8C=E9=87=8D?= =?UTF-8?q?=E6=9E=84=20version/runtime=20=E7=9A=84=E5=86=85=E9=83=A8?= =?UTF-8?q?=E8=B0=83=E7=94=A8=E9=93=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修改了 system 的显示方式将 os名称/版本/架构 移为了一行 - 将 version/runtime 的执行体移动到了 MornyInformations 当中 - MornyInformations 中对一些复杂的 version/runtime 部件为其独立出了一个方法 --- gradle.properties | 2 +- .../cono/morny/bot/command/MornyCommands.java | 100 +----------- .../morny/bot/command/MornyInformations.java | 147 ++++++++++++++++-- .../cono/morny/daemon/MornyReport.java | 9 +- 4 files changed, 144 insertions(+), 114 deletions(-) diff --git a/gradle.properties b/gradle.properties index 50b2c53..c087a4f 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-beta1 +VERSION = 1.0.0-beta2 USE_DELTA = false VERSION_DELTA = diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyCommands.java b/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyCommands.java index e50db1b..5e14712 100644 --- a/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyCommands.java +++ b/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyCommands.java @@ -1,8 +1,6 @@ package cc.sukazyo.cono.morny.bot.command; -import cc.sukazyo.cono.morny.BuildConfig; import cc.sukazyo.cono.morny.MornyCoeur; -import cc.sukazyo.cono.morny.MornySystem; import cc.sukazyo.cono.morny.bot.event.OnUniMeowTrigger; import cc.sukazyo.cono.morny.daemon.MornyReport; import cc.sukazyo.cono.morny.data.MornyJrrp; @@ -21,13 +19,9 @@ import org.jetbrains.annotations.NotNull; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import java.net.InetAddress; -import java.net.UnknownHostException; import java.util.*; import static cc.sukazyo.cono.morny.Log.logger; -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 MornyCommands { @@ -234,33 +228,7 @@ public class MornyCommands { @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) { onCommandVersionExec(event); } - } - public static void onCommandVersionExec (@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 "+ (MornySystem.currentCodePath()==null ? - String.format("%s", BuildConfig.COMMIT.substring(0, 8)) : - String.format("%s", MornySystem.currentCodePath(), BuildConfig.COMMIT.substring(0, 8)) - ) + (MornySystem.isCleanBuild() ? "" : ".δ") : "", - escapeHtml(MornySystem.getJarMd5()), - BuildConfig.CODE_TIMESTAMP, - escapeHtml(formatDate(BuildConfig.CODE_TIMESTAMP, 0)) - ) - ).replyToMessageId(event.message().messageId()).parseMode(ParseMode.HTML)); + @Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { MornyInformations.echoVersion(event); } } private static class MornyRuntime implements ISimpleCommand { @@ -268,71 +236,7 @@ public class MornyCommands { @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) { onCommandRuntimeExec(event); } - } - /** - * @since 0.4.1.2 - */ - public static void onCommandRuntimeExec (@Nonnull Update event) { - String hostname; - try { - hostname = InetAddress.getLocalHost().getHostName(); - } catch (UnknownHostException e) { - hostname = ""; - } - MornyCoeur.extra().exec(new SendMessage( - event.message().chat().id(), - String.format(""" - system: - - %s - - %s - - %s - java runtime: - - %s - - %s - vm memory: - - %d / %d MB - - %d cores - coeur version: - - %s%s%s*%s - - %s - - %s [UTC] - - [%d] - continuous: - - %s - - [%d] - - %s [UTC] - - [%d]""", - // system - escapeHtml(hostname), - escapeHtml(String.format("%s (%s)", System.getProperty("os.name"), 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 - escapeHtml(MornySystem.VERSION_BASE), - MornySystem.isUseDelta() ? String.format("-δ%s", escapeHtml(Objects.requireNonNull(MornySystem.VERSION_DELTA))) : "", - MornySystem.isGitBuild()?String.format("-git.%s%s", MornySystem.currentCodePath()==null ? ( - String.format("%s", BuildConfig.COMMIT.substring(0, 8)) - ) : ( - String.format("%s", MornySystem.currentCodePath(), BuildConfig.COMMIT.substring(0, 8)) - ), MornySystem.isCleanBuild()?"":".δ"):"", - escapeHtml(MornySystem.CODENAME.toUpperCase()), - 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)); + @Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { MornyInformations.echoRuntime(event); } } private static class Jrrp implements ITelegramCommand { diff --git a/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyInformations.java b/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyInformations.java index 5558f6e..e9a6ad2 100644 --- a/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyInformations.java +++ b/src/main/java/cc/sukazyo/cono/morny/bot/command/MornyInformations.java @@ -1,14 +1,25 @@ package cc.sukazyo.cono.morny.bot.command; +import cc.sukazyo.cono.morny.BuildConfig; import cc.sukazyo.cono.morny.MornyCoeur; +import cc.sukazyo.cono.morny.MornySystem; 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.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 MornyInformations implements ITelegramCommand { @@ -26,7 +37,7 @@ public class MornyInformations implements ITelegramCommand { public void execute (@Nonnull InputCommand command, @Nonnull Update event) { if (!command.hasArgs()) { - MornyCommands.onCommandRuntimeExec(event); + echoRuntime(event); return; } @@ -35,9 +46,9 @@ public class MornyInformations implements ITelegramCommand { if (action.startsWith(SUB_STICKER)) { echoStickers(command, event); } else if (action.equals(SUB_RUNTIME)) { - echoRuntime(command, event); + echoRuntime(event); } else if (action.equals(SUB_VERSION) || action.equals(SUB_VERSION_2)) { - echoVersion(command, event); + echoVersion(event); } else { echo404(event); } @@ -85,20 +96,134 @@ public class MornyInformations implements ITelegramCommand { * /info 子命令 {@value #SUB_RUNTIME} * @since 1.0.0-alpha4 */ - public static void echoRuntime (@Nonnull InputCommand command, @Nonnull Update event) { - if (command.getArgs().length == 1) - MornyCommands.onCommandRuntimeExec(event); - else echo404(event); + 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)); } /** * /info 子命令 {@value #SUB_VERSION} * @since 1.0.0-alpha4 */ - public static void echoVersion (@Nonnull InputCommand command, @Nonnull Update event) { - if (command.getArgs().length == 1) - MornyCommands.onCommandVersionExec(event); - else echo404(event); + 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; + } } private static void echo404 (@Nonnull Update event) { diff --git a/src/main/java/cc/sukazyo/cono/morny/daemon/MornyReport.java b/src/main/java/cc/sukazyo/cono/morny/daemon/MornyReport.java index c79b223..b4f7ae5 100644 --- a/src/main/java/cc/sukazyo/cono/morny/daemon/MornyReport.java +++ b/src/main/java/cc/sukazyo/cono/morny/daemon/MornyReport.java @@ -1,8 +1,7 @@ package cc.sukazyo.cono.morny.daemon; -import cc.sukazyo.cono.morny.Log; -import cc.sukazyo.cono.morny.MornyCoeur; -import cc.sukazyo.cono.morny.MornyConfig; +import cc.sukazyo.cono.morny.*; +import cc.sukazyo.cono.morny.bot.command.MornyInformations; import cc.sukazyo.cono.morny.util.tgapi.event.EventRuntimeException; import cc.sukazyo.cono.morny.util.tgapi.formatting.TGToString; import com.google.gson.GsonBuilder; @@ -74,16 +73,18 @@ public class MornyReport { * morny 登陆时的报告发送,包含已登录的账号 id 以及启动配置。 * @since 1.0.0-alpha6 */ - public static void onMornyLogIn () { + static void onMornyLogIn () { executeReport(new SendMessage( MornyCoeur.config().reportToChat, String.format(""" ▌Morny Logged in + -v %s as user @%s as config fields: %s """, + MornyInformations.getVersionAllFullTagHtml(), MornyCoeur.getUsername(), sectionConfigFields(MornyCoeur.config()) )