使 MornyCoeur 和 MornyTrusted 对象封装,添加 master 和 trustedChat 定义参数

This commit is contained in:
A.C.Sukazyo Eyre 2021-12-22 00:43:56 +08:00
parent 6a5a23b6be
commit def7ee79c2
Signed by: Eyre_S
GPG Key ID: EFB47D98FE082FAD
9 changed files with 135 additions and 43 deletions

View File

@ -1,6 +1,6 @@
## Core ## Core
VERSION = 0.4.2.6 VERSION = 0.4.2.7
# dependencies # dependencies

View File

@ -4,6 +4,6 @@ package cc.sukazyo.cono.morny;
* the final field that will be updated by gradle automatically. * the final field that will be updated by gradle automatically.
*/ */
public class GradleProjectConfigures { public class GradleProjectConfigures {
public static final String VERSION = "0.4.2.6"; public static final String VERSION = "0.4.2.7";
public static final long COMPILE_TIMESTAMP = 1640065256004L; public static final long COMPILE_TIMESTAMP = 1640104964102L;
} }

View File

@ -17,8 +17,14 @@ import static cc.sukazyo.cono.morny.Log.logger;
*/ */
public class MornyCoeur { public class MornyCoeur {
/** 当前程序的 Morny Coeur 实例 */
private static MornyCoeur INSTANCE;
/** 当前 Morny 的{@link MornyTrusted 信任验证机}实例 */
private final MornyTrusted trusted;
/** morny 的 bot 账户 */ /** morny 的 bot 账户 */
private static TelegramBot account; private final TelegramBot account;
/** /**
* morny bot 账户的用户名<br> * morny bot 账户的用户名<br>
* <br> * <br>
@ -28,36 +34,40 @@ public class MornyCoeur {
* 如果在登陆之前就定义了此字段则登陆代码会验证登陆的 bot username * 如果在登陆之前就定义了此字段则登陆代码会验证登陆的 bot username
* 是否与定义的 username 符合如果不符合则会报错 * 是否与定义的 username 符合如果不符合则会报错
*/ */
private static String username; private final String username;
/** /**
* morny 的事件忽略前缀时间<br> * morny 的事件忽略前缀时间<br>
* <br> * <br>
* {@link cc.sukazyo.cono.morny.bot.event.OnUpdateTimestampOffsetLock} * {@link cc.sukazyo.cono.morny.bot.event.OnUpdateTimestampOffsetLock}
* 会根据这里定义的时间戳取消掉比此时间更早的事件链 * 会根据这里定义的时间戳取消掉比此时间更早的事件链
*/ */
public static long latestEventTimestamp; public long latestEventTimestamp;
/** /**
* morny 主程序启动时间<br> * morny 主程序启动时间<br>
* 用于统计数据 * 用于统计数据
*/ */
public static final long coeurStartTimestamp = System.currentTimeMillis(); public static final long coeurStartTimestamp = System.currentTimeMillis();
private record LogInResult(TelegramBot account, String username) { }
/** /**
* bot 启动入口执行 bot 初始化 * 执行 bot 初始化
* *
* @param botKey bot telegram bot api token * @param botKey bot telegram bot api token
* @param botUsername bot username 限定如果为 null 则表示不限定 * @param botUsername bot username 限定如果为 null 则表示不限定
* 如果指定则登录时会检查所登陆的 bot 的用户名是否与此相等 * 如果指定则登录时会检查所登陆的 bot 的用户名是否与此相等
* @param master morny 实例所信任的主人的 id用于初始化 {@link #trusted}
* @param trustedChat morny 实例所信任的群组的 id用于初始化 {@link #trusted}
* @param latestEventTimestamp 事件处理器会处理事件的最早时间戳 * @param latestEventTimestamp 事件处理器会处理事件的最早时间戳
* 只有限定的 message 事件会受此影响 * 只有限定的 message 事件会受此影响
* 单位为毫秒 * 单位为毫秒
*/ */
public static void main (@Nonnull String botKey, @Nullable String botUsername, long latestEventTimestamp) { private MornyCoeur (
@Nonnull String botKey, @Nullable String botUsername,
MornyCoeur.latestEventTimestamp = latestEventTimestamp; long master, long trustedChat, long latestEventTimestamp
) {
logger.info("System Starting");
this.latestEventTimestamp = latestEventTimestamp;
configureSafeExit(); configureSafeExit();
logger.info("args key:\n " + botKey); logger.info("args key:\n " + botKey);
@ -65,23 +75,57 @@ public class MornyCoeur {
logger.info("login as:\n " + botUsername); logger.info("login as:\n " + botUsername);
} }
try { account = login(botKey); } try {
catch (Exception e) { logger.error("Cannot login to bot/api. :\n " + e.getMessage()); System.exit(-1); } final LogInResult loginResult = login(botKey);
this.account = loginResult.account;
this.username = loginResult.username;
this.trusted = new MornyTrusted(master, trustedChat);
logger.info(String.format("""
trusted param set:
- master (id)
%d
- trusted chat (id)
%d""",
master, trustedChat
));
}
catch (Exception e) {
RuntimeException ex = new RuntimeException("Cannot login to bot/api. :\n " + e.getMessage());
logger.error(ex.getMessage());
throw ex;
}
logger.info("Bot login succeed."); logger.info("Bot login succeed.");
TrackerDataManager.init(); }
EventListeners.registerAllListeners();
account.setUpdatesListener(OnUpdate::onNormalUpdate); /**
* 向外界暴露的 morny 初始化入口.
logger.info("System start complete"); * <p>
* 如果 morny 已经初始化则不会进行初始化抛出错误消息并直接退出方法
*
* @see #MornyCoeur 程序初始化方法
*/
public static void main (
@Nonnull String botKey, @Nullable String botUsername,
long master, long trustedChat, long latestEventTimestamp
) {
if (INSTANCE == null) {
logger.info("System Starting");
INSTANCE = new MornyCoeur(botKey, botUsername, master, trustedChat, latestEventTimestamp);
TrackerDataManager.init();
EventListeners.registerAllListeners();
INSTANCE.account.setUpdatesListener(OnUpdate::onNormalUpdate);
logger.info("System start complete");
return;
}
logger.error("System already started coeur!!!");
} }
/** /**
* 用于退出时进行缓存的任务处理等进行安全退出 * 用于退出时进行缓存的任务处理等进行安全退出
*/ */
private static void exitCleanup () { private void exitCleanup () {
TrackerDataManager.DAEMON.interrupt(); TrackerDataManager.DAEMON.interrupt();
TrackerDataManager.trackingLock.lock(); TrackerDataManager.trackingLock.lock();
} }
@ -89,8 +133,8 @@ public class MornyCoeur {
/** /**
* 为程序在虚拟机上添加退出钩子 * 为程序在虚拟机上添加退出钩子
*/ */
private static void configureSafeExit () { private void configureSafeExit () {
Runtime.getRuntime().addShutdownHook(new Thread(MornyCoeur::exitCleanup)); Runtime.getRuntime().addShutdownHook(new Thread(this::exitCleanup));
} }
/** /**
@ -104,18 +148,17 @@ public class MornyCoeur {
* @return 成功登录后的 {@link TelegramBot} 对象 * @return 成功登录后的 {@link TelegramBot} 对象
*/ */
@Nonnull @Nonnull
public static TelegramBot login (@Nonnull String key) { private LogInResult login (@Nonnull String key) {
final TelegramBot account = new TelegramBot(key); final TelegramBot account = new TelegramBot(key);
logger.info("Trying to login..."); logger.info("Trying to login...");
for (int i = 1; i < 4; i++) { for (int i = 1; i < 4; i++) {
if (i != 1) logger.info("retrying..."); if (i != 1) logger.info("retrying...");
try { try {
final String username = account.execute(new GetMe()).user().username(); final String username = account.execute(new GetMe()).user().username();
if (MornyCoeur.username != null && !MornyCoeur.username.equals(username)) if (this.username != null && !this.username.equals(username))
throw new RuntimeException("Required the bot @" + MornyCoeur.username + " but @" + username + " logged in!"); throw new RuntimeException("Required the bot @" + this.username + " but @" + username + " logged in!");
else MornyCoeur.username = username;
logger.info("Succeed login to @" + username); logger.info("Succeed login to @" + username);
return account; return new LogInResult(account, username);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(System.out); e.printStackTrace(System.out);
logger.error("login failed."); logger.error("login failed.");
@ -129,8 +172,9 @@ public class MornyCoeur {
* *
* @return {@link #account MornyCoeur.account} * @return {@link #account MornyCoeur.account}
*/ */
@Nonnull
public static TelegramBot getAccount () { public static TelegramBot getAccount () {
return account; return INSTANCE.account;
} }
/** /**
@ -138,8 +182,29 @@ public class MornyCoeur {
* *
* @return {@link #username MornyCoeur.username} * @return {@link #username MornyCoeur.username}
*/ */
@Nonnull
public static String getUsername () { public static String getUsername () {
return username; return INSTANCE.username;
}
/**
*
* 获取忽略时间点
*
* @return {@link #latestEventTimestamp MornyCoeur.latestEventTimestamp}
*/
public static long getLatestEventTimestamp () {
return INSTANCE.latestEventTimestamp;
}
/**
* 获取 Morny {@link MornyTrusted 信任验证机}
*
* @return {@link #trusted MornyCoeur.trusted}
*/
@Nonnull
public static MornyTrusted trustedInstance () {
return INSTANCE.trusted;
} }
} }

View File

@ -12,13 +12,18 @@ public class MornyTrusted {
* 群聊id其指向的群聊指示了哪个群的成员是受信任的 * 群聊id其指向的群聊指示了哪个群的成员是受信任的
* @see #isTrusted(long) 受信检查 * @see #isTrusted(long) 受信检查
*/ */
public static final long TRUSTED_CHAT_ID = -1001541451710L; public final Long TRUSTED_CHAT_ID;
/** /**
* morny 的主人<br> * morny 的主人<br>
* 这项值的对象总是会被认为是可信任的 * 这项值的对象总是会被认为是可信任的
*/ */
public static final long MASTER = 793274677L; public final long MASTER;
public MornyTrusted (long master, long trustedChatId) {
this.TRUSTED_CHAT_ID = trustedChatId;
this.MASTER = master;
}
/** /**
* 用于检查一个 telegram-user 是否受信任<br> * 用于检查一个 telegram-user 是否受信任<br>
@ -30,7 +35,7 @@ public class MornyTrusted {
* @param userId 需要检查的用户的id * @param userId 需要检查的用户的id
* @return 所传递的用户id对应的用户是否受信任 * @return 所传递的用户id对应的用户是否受信任
*/ */
public static boolean isTrusted (long userId) { public boolean isTrusted (long userId) {
if (userId == MASTER) return true; if (userId == MASTER) return true;
final ChatMember chatMember = MornyCoeur.getAccount().execute(new GetChatMember(TRUSTED_CHAT_ID, userId)).chatMember(); final ChatMember chatMember = MornyCoeur.getAccount().execute(new GetChatMember(TRUSTED_CHAT_ID, userId)).chatMember();
return ( return (

View File

@ -59,7 +59,7 @@ public class ServerMain {
* <s>但实际上这并不影响现在的使用选项赋值目前仍属于测试功能</s><br> * <s>但实际上这并不影响现在的使用选项赋值目前仍属于测试功能</s><br>
* <b>但请勿混用</b>这将使两个赋值出现混淆并<b>产生不可知的结果</b> * <b>但请勿混用</b>这将使两个赋值出现混淆并<b>产生不可知的结果</b>
* *
* @see MornyCoeur#main(String, String, long) * @see MornyCoeur#main(String, String, long, long, long)
* @since 0.4.0.0 * @since 0.4.0.0
* @param args 参数组 * @param args 参数组
*/ */
@ -68,6 +68,8 @@ public class ServerMain {
String key = null; String key = null;
String username = null; String username = null;
boolean outdatedBlock = false; boolean outdatedBlock = false;
long master = 793274677L;
long trustedChat = -1001541451710L;
for (int i = 0; i < args.length; i++) { for (int i = 0; i < args.length; i++) {
@ -100,6 +102,16 @@ public class ServerMain {
username = args[i]; username = args[i];
continue; continue;
} }
case "--master" -> {
i++;
master = Long.parseLong(args[i]);
continue;
}
case "--trusted-chat" -> {
i++;
trustedChat = Long.parseLong(args[i]);
continue;
}
} }
} else { } else {
@ -143,7 +155,7 @@ public class ServerMain {
if (welcomeEchoMode) return; if (welcomeEchoMode) return;
assert key != null; assert key != null;
MornyCoeur.main(key, username, outdatedBlock?System.currentTimeMillis():0); MornyCoeur.main(key, username, master, trustedChat, outdatedBlock?System.currentTimeMillis():0);
} }

View File

@ -23,7 +23,7 @@ public class OnCallMe extends EventListener {
* 跟随 {@link MornyTrusted#MASTER} 的值 * 跟随 {@link MornyTrusted#MASTER} 的值
* @since 0.4.2.1 * @since 0.4.2.1
*/ */
private static final long ME = MornyTrusted.MASTER; private static final long ME = MornyCoeur.trustedInstance().MASTER;
/** /**
* 监听私聊 bot 的消息进行呼叫关键字匹配 * 监听私聊 bot 的消息进行呼叫关键字匹配

View File

@ -3,7 +3,6 @@ package cc.sukazyo.cono.morny.bot.event;
import cc.sukazyo.cono.morny.GradleProjectConfigures; import cc.sukazyo.cono.morny.GradleProjectConfigures;
import cc.sukazyo.cono.morny.MornyCoeur; import cc.sukazyo.cono.morny.MornyCoeur;
import cc.sukazyo.cono.morny.MornySystem; import cc.sukazyo.cono.morny.MornySystem;
import cc.sukazyo.cono.morny.MornyTrusted;
import cc.sukazyo.cono.morny.bot.api.EventListener; import cc.sukazyo.cono.morny.bot.api.EventListener;
import cc.sukazyo.cono.morny.bot.api.InputCommand; import cc.sukazyo.cono.morny.bot.api.InputCommand;
import cc.sukazyo.cono.morny.bot.event.on_commands.EventHack; import cc.sukazyo.cono.morny.bot.event.on_commands.EventHack;
@ -88,7 +87,7 @@ public class OnCommandExecute extends EventListener {
} }
private void onCommandExitExec (@Nonnull Update event) { private void onCommandExitExec (@Nonnull Update event) {
if (MornyTrusted.isTrusted(event.message().from().id())) { if (MornyCoeur.trustedInstance().isTrusted(event.message().from().id())) {
MornyCoeur.getAccount().execute(new SendSticker( MornyCoeur.getAccount().execute(new SendSticker(
event.message().chat().id(), event.message().chat().id(),
TelegramStickers.ID_EXIT TelegramStickers.ID_EXIT

View File

@ -17,30 +17,41 @@ import javax.annotation.Nonnull;
* <li>{@link EventListener#onChannelPost(Update) 收到频道消息}</li> * <li>{@link EventListener#onChannelPost(Update) 收到频道消息}</li>
* <li>{@link EventListener#onEditedChannelPost(Update) 频道消息被更新}</li> * <li>{@link EventListener#onEditedChannelPost(Update) 频道消息被更新}</li>
* </ul> * </ul>
* @see #isOutdated 时间判断
*/ */
public class OnUpdateTimestampOffsetLock extends EventListener { public class OnUpdateTimestampOffsetLock extends EventListener {
/**
* 检查传入时间是否在要求时间之前"过期".
* @param timestamp 传入时间秒级
* @return 如果传入时间在要求时间<u>之前</u>返回true反之false
* @since 0.4.2.7
*/
public boolean isOutdated(long timestamp) {
return timestamp < MornyCoeur.getLatestEventTimestamp()/1000;
}
@Override @Override
public boolean onMessage (@NotNull Update update) { public boolean onMessage (@NotNull Update update) {
return update.message().date() < MornyCoeur.latestEventTimestamp/1000; return isOutdated(update.message().date());
} }
/** @since 0.4.2.6 */ /** @since 0.4.2.6 */
@Override @Override
public boolean onEditedMessage (@Nonnull Update update) { public boolean onEditedMessage (@Nonnull Update update) {
return update.editedMessage().editDate() < MornyCoeur.latestEventTimestamp/1000; return isOutdated(update.editedMessage().editDate());
} }
/** @since 0.4.2.6 */ /** @since 0.4.2.6 */
@Override @Override
public boolean onChannelPost (@Nonnull Update update) { public boolean onChannelPost (@Nonnull Update update) {
return update.channelPost().date() < MornyCoeur.latestEventTimestamp/1000; return isOutdated(update.channelPost().date());
} }
/** @since 0.4.2.6 */ /** @since 0.4.2.6 */
@Override @Override
public boolean onEditedChannelPost (@Nonnull Update update) { public boolean onEditedChannelPost (@Nonnull Update update) {
return update.editedChannelPost().editDate() < MornyCoeur.latestEventTimestamp/1000; return isOutdated(update.editedChannelPost().editDate());
} }
} }

View File

@ -36,7 +36,7 @@ public class EventHack {
switch (x_mode) { switch (x_mode) {
case "any": case "any":
if (MornyTrusted.isTrusted(event.message().from().id())) { if (MornyCoeur.trustedInstance().isTrusted(event.message().from().id())) {
OnEventHackHandle.registerHack( OnEventHackHandle.registerHack(
event.message().messageId(), event.message().messageId(),
event.message().from().id(), event.message().from().id(),