mirror of
https://github.com/Eyre-S/Coeur-Morny-Cono.git
synced 2024-11-24 20:17:38 +08:00
scala port stage2 (not tested)
This commit is contained in:
parent
aafdcc1fb2
commit
1a31a22cd9
@ -99,8 +99,8 @@ scala {
|
||||
|
||||
compileJava {
|
||||
|
||||
sourceCompatibility '17'
|
||||
targetCompatibility '17'
|
||||
sourceCompatibility proj_java.getMajorVersion()
|
||||
targetCompatibility proj_java.getMajorVersion()
|
||||
|
||||
options.encoding = proj_file_encoding.name()
|
||||
|
||||
@ -108,9 +108,14 @@ scala {
|
||||
|
||||
compileScala {
|
||||
|
||||
sourceCompatibility proj_java.getMajorVersion()
|
||||
targetCompatibility proj_java.getMajorVersion()
|
||||
|
||||
options.encoding = proj_file_encoding.name()
|
||||
scalaCompileOptions.encoding = proj_file_encoding.name()
|
||||
|
||||
// scalaCompileOptions.additionalParameters.add("-Yexplicit-nulls")
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ MORNY_COMMIT_PATH = https://github.com/Eyre-S/Coeur-Morny-Cono/commit/%s
|
||||
VERSION = 1.0.0-RC4
|
||||
|
||||
USE_DELTA = true
|
||||
VERSION_DELTA = scalaport1
|
||||
VERSION_DELTA = scalaport2
|
||||
|
||||
CODENAME = beiping
|
||||
|
||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
@ -5,6 +5,7 @@ import cc.sukazyo.messiva.log.LogLevel;
|
||||
import cc.sukazyo.messiva.logger.Logger;
|
||||
import cc.sukazyo.messiva.appender.ConsoleAppender;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
||||
@ -48,7 +49,7 @@ public class Log {
|
||||
* @return {@link String} 格式的异常的堆栈报告信息.
|
||||
* @see 1.0.0-alpha5
|
||||
*/
|
||||
public static String exceptionLog (Exception e) {
|
||||
public static String exceptionLog (@Nonnull Throwable e) {
|
||||
final StringWriter stackTrace = new StringWriter();
|
||||
e.printStackTrace(new PrintWriter(stackTrace));
|
||||
return stackTrace.toString();
|
||||
|
@ -1,8 +1,8 @@
|
||||
package cc.sukazyo.cono.morny;
|
||||
|
||||
import cc.sukazyo.cono.morny.bot.api.OnUpdate;
|
||||
import cc.sukazyo.cono.morny.bot.api.TelegramUpdatesListener$;
|
||||
import cc.sukazyo.cono.morny.bot.command.MornyCommands;
|
||||
import cc.sukazyo.cono.morny.bot.event.EventListeners;
|
||||
import cc.sukazyo.cono.morny.bot.event.MornyEventListeners;
|
||||
import cc.sukazyo.cono.morny.bot.query.MornyQueries;
|
||||
import cc.sukazyo.cono.morny.daemon.MornyDaemons;
|
||||
import cc.sukazyo.cono.morny.daemon.TrackerDataManager;
|
||||
@ -31,8 +31,6 @@ public class MornyCoeur {
|
||||
|
||||
/** 当前 Morny 的{@link MornyTrusted 信任验证机}实例 */
|
||||
private final MornyTrusted trusted;
|
||||
/** 当前 Morny 的 telegram 命令管理器 */
|
||||
private final MornyCommands commandManager = new MornyCommands();
|
||||
private final MornyQueries queryManager = new MornyQueries();
|
||||
|
||||
/** morny 的 bot 账户 */
|
||||
@ -127,12 +125,12 @@ public class MornyCoeur {
|
||||
MornyDaemons.start();
|
||||
|
||||
logger.info("start telegram events listening");
|
||||
EventListeners.registerAllListeners();
|
||||
INSTANCE.account.setUpdatesListener(OnUpdate::onNormalUpdate);
|
||||
MornyEventListeners.registerAllEvents();
|
||||
INSTANCE.account.setUpdatesListener(TelegramUpdatesListener$.MODULE$);
|
||||
|
||||
if (config.commandLoginRefresh) {
|
||||
logger.info("resetting telegram command list");
|
||||
commandManager().automaticUpdateList();
|
||||
MornyCommands.automaticTGListUpdate();
|
||||
}
|
||||
|
||||
logger.info("Coeur start complete");
|
||||
@ -156,7 +154,7 @@ public class MornyCoeur {
|
||||
private void exitCleanup () {
|
||||
MornyDaemons.stop();
|
||||
if (config.commandLogoutClear) {
|
||||
commandManager.automaticRemoveList();
|
||||
MornyCommands.automaticTGListRemove();
|
||||
}
|
||||
}
|
||||
|
||||
@ -288,11 +286,6 @@ public class MornyCoeur {
|
||||
return INSTANCE.trusted;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static MornyCommands commandManager () {
|
||||
return INSTANCE.commandManager;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static MornyQueries queryManager () {
|
||||
return INSTANCE.queryManager;
|
||||
|
@ -1,66 +0,0 @@
|
||||
package cc.sukazyo.cono.morny.bot.api;
|
||||
|
||||
import com.pengrad.telegrambot.model.Update;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public abstract class EventListener {
|
||||
|
||||
public boolean onMessage (@Nonnull Update update) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onEditedMessage (@Nonnull Update update) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onChannelPost (@Nonnull Update update) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onEditedChannelPost (@Nonnull Update update) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onInlineQuery (@Nonnull Update update) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onChosenInlineResult (@Nonnull Update update) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onCallbackQuery (@Nonnull Update update) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onShippingQuery (@Nonnull Update update) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onPreCheckoutQuery (@Nonnull Update update) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onPoll (@Nonnull Update update) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onPollAnswer (@Nonnull Update update) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onMyChatMemberUpdated (@Nonnull Update update) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onChatMemberUpdated (@Nonnull Update update) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onChatJoinRequest (@Nonnull Update update) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -1,118 +0,0 @@
|
||||
package cc.sukazyo.cono.morny.bot.api;
|
||||
|
||||
import cc.sukazyo.cono.morny.Log;
|
||||
import cc.sukazyo.cono.morny.daemon.MornyReport;
|
||||
import cc.sukazyo.cono.morny.util.tgapi.event.EventRuntimeException;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.pengrad.telegrambot.model.Update;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static cc.sukazyo.cono.morny.Log.logger;
|
||||
|
||||
public class EventListenerManager {
|
||||
|
||||
private static final List<EventListener> listeners = new ArrayList<>();
|
||||
|
||||
private static class EventPublisher extends Thread {
|
||||
|
||||
private final Function<EventListener, Boolean> exec;
|
||||
|
||||
public EventPublisher(@Nonnull Update update, @Nonnull Function<EventListener, Boolean> exec) {
|
||||
this.setName("EVT"+update.updateId());
|
||||
this.exec = exec;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run () {
|
||||
for (EventListener x : listeners) {
|
||||
try {
|
||||
|
||||
if (exec.apply(x)) return;
|
||||
|
||||
} catch (Exception e) {
|
||||
|
||||
final StringBuilder errorMessage = new StringBuilder();
|
||||
errorMessage.append("Event throws unexpected exception:\n");
|
||||
errorMessage.append(Log.exceptionLog(e).indent(4));
|
||||
if (e instanceof EventRuntimeException.ActionFailed) {
|
||||
errorMessage.append("\ntg-api action: response track: ");
|
||||
errorMessage.append(new GsonBuilder().setPrettyPrinting().create().toJson(
|
||||
((EventRuntimeException.ActionFailed)e).getResponse()
|
||||
).indent(4)).append('\n');
|
||||
}
|
||||
logger.error(errorMessage.toString());
|
||||
|
||||
MornyReport.exception(e, "on event running");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void addListener (@Nonnull EventListener... listeners) {
|
||||
EventListenerManager.listeners.addAll(Arrays.asList(listeners));
|
||||
}
|
||||
|
||||
public static void publishMessageEvent (@Nonnull Update update) {
|
||||
new EventPublisher(update, x -> x.onMessage(update)).start();
|
||||
}
|
||||
|
||||
public static void publishEditedMessageEvent (@Nonnull Update update) {
|
||||
new EventPublisher(update, x -> x.onEditedMessage(update)).start();
|
||||
}
|
||||
|
||||
public static void publishChannelPostEvent (@Nonnull Update update) {
|
||||
new EventPublisher(update, x -> x.onChannelPost(update)).start();
|
||||
}
|
||||
|
||||
public static void publishEditedChannelPostEvent (@Nonnull Update update) {
|
||||
new EventPublisher(update, x -> x.onEditedChannelPost(update)).start();
|
||||
}
|
||||
|
||||
public static void publishInlineQueryEvent (@Nonnull Update update) {
|
||||
new EventPublisher(update, x -> x.onInlineQuery(update)).start();
|
||||
}
|
||||
|
||||
public static void publishChosenInlineResultEvent (@Nonnull Update update) {
|
||||
new EventPublisher(update, x -> x.onChosenInlineResult(update)).start();
|
||||
}
|
||||
|
||||
public static void publishCallbackQueryEvent (@Nonnull Update update) {
|
||||
new EventPublisher(update, x -> x.onCallbackQuery(update)).start();
|
||||
}
|
||||
|
||||
public static void publishShippingQueryEvent (@Nonnull Update update) {
|
||||
new EventPublisher(update, x -> x.onShippingQuery(update)).start();
|
||||
}
|
||||
|
||||
public static void publishPreCheckoutQueryEvent (@Nonnull Update update) {
|
||||
new EventPublisher(update, x -> x.onPreCheckoutQuery(update)).start();
|
||||
}
|
||||
|
||||
public static void publishPollEvent (@Nonnull Update update) {
|
||||
new EventPublisher(update, x -> x.onPoll(update)).start();
|
||||
}
|
||||
|
||||
public static void publishPollAnswerEvent (@Nonnull Update update) {
|
||||
new EventPublisher(update, x -> x.onPollAnswer(update)).start();
|
||||
}
|
||||
|
||||
public static void publishMyChatMemberUpdatedEvent (@Nonnull Update update) {
|
||||
new EventPublisher(update, x -> x.onMyChatMemberUpdated(update)).start();
|
||||
}
|
||||
|
||||
public static void publishChatMemberUpdatedEvent (@Nonnull Update update) {
|
||||
new EventPublisher(update, x -> x.onChatMemberUpdated(update)).start();
|
||||
}
|
||||
|
||||
public static void publishChatJoinRequestEvent (@Nonnull Update update) {
|
||||
new EventPublisher(update, x -> x.onChatJoinRequest(update)).start();
|
||||
}
|
||||
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
package cc.sukazyo.cono.morny.bot.api;
|
||||
|
||||
import com.pengrad.telegrambot.model.request.InlineQueryResult;
|
||||
|
||||
public class InlineQueryUnit<T extends InlineQueryResult<T>> {
|
||||
|
||||
public static final int DEFAULT_INLINE_CACHE_TIME = 300;
|
||||
public static final boolean DEFAULT_INLINE_PERSONAL_RESP = false;
|
||||
|
||||
private int cacheTime = DEFAULT_INLINE_CACHE_TIME;
|
||||
private boolean isPersonal = DEFAULT_INLINE_PERSONAL_RESP;
|
||||
public final T result;
|
||||
|
||||
public InlineQueryUnit (T result) {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public int cacheTime () {
|
||||
return cacheTime;
|
||||
}
|
||||
|
||||
public InlineQueryUnit<T> cacheTime (int cacheTime) {
|
||||
this.cacheTime = cacheTime;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isPersonal () {
|
||||
return isPersonal;
|
||||
}
|
||||
|
||||
public InlineQueryUnit<T> isPersonal (boolean isPersonal) {
|
||||
this.isPersonal = isPersonal;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
package cc.sukazyo.cono.morny.bot.api;
|
||||
|
||||
import com.pengrad.telegrambot.UpdatesListener;
|
||||
import com.pengrad.telegrambot.model.Update;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.List;
|
||||
|
||||
public class OnUpdate {
|
||||
|
||||
public static int onNormalUpdate (@Nonnull List<Update> updates) {
|
||||
for (Update update : updates) {
|
||||
if (update.message() != null) {
|
||||
EventListenerManager.publishMessageEvent(update);
|
||||
}
|
||||
if (update.editedMessage() != null) {
|
||||
EventListenerManager.publishEditedMessageEvent(update);
|
||||
}
|
||||
if (update.channelPost() != null) {
|
||||
EventListenerManager.publishChannelPostEvent(update);
|
||||
}
|
||||
if (update.editedChannelPost() != null) {
|
||||
EventListenerManager.publishEditedChannelPostEvent(update);
|
||||
}
|
||||
if (update.inlineQuery() != null) {
|
||||
EventListenerManager.publishInlineQueryEvent(update);
|
||||
}
|
||||
if (update.chosenInlineResult() != null) {
|
||||
EventListenerManager.publishChosenInlineResultEvent(update);
|
||||
}
|
||||
if (update.callbackQuery() != null) {
|
||||
EventListenerManager.publishCallbackQueryEvent(update);
|
||||
}
|
||||
if (update.shippingQuery() != null) {
|
||||
EventListenerManager.publishShippingQueryEvent(update);
|
||||
}
|
||||
if (update.preCheckoutQuery() != null) {
|
||||
EventListenerManager.publishPreCheckoutQueryEvent(update);
|
||||
}
|
||||
if (update.poll() != null) {
|
||||
EventListenerManager.publishPollEvent(update);
|
||||
}
|
||||
if (update.pollAnswer() != null) {
|
||||
EventListenerManager.publishPollAnswerEvent(update);
|
||||
}
|
||||
if (update.myChatMember() != null) {
|
||||
EventListenerManager.publishMyChatMemberUpdatedEvent(update);
|
||||
}
|
||||
if (update.chatMember() != null) {
|
||||
EventListenerManager.publishChatMemberUpdatedEvent(update);
|
||||
}
|
||||
if (update.chatJoinRequest() != null) {
|
||||
EventListenerManager.publishChatJoinRequestEvent(update);
|
||||
}
|
||||
}
|
||||
return UpdatesListener.CONFIRMED_UPDATES_ALL;
|
||||
}
|
||||
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
package cc.sukazyo.cono.morny.bot.command;
|
||||
|
||||
import cc.sukazyo.cono.morny.util.tgapi.InputCommand;
|
||||
import com.pengrad.telegrambot.model.Update;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public interface ISimpleCommand {
|
||||
|
||||
@Nonnull
|
||||
String getName();
|
||||
|
||||
@Nullable
|
||||
String[] getAliases();
|
||||
|
||||
void execute (@Nonnull InputCommand command, @Nonnull Update event);
|
||||
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
package cc.sukazyo.cono.morny.bot.command;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public interface ITelegramCommand extends ISimpleCommand {
|
||||
|
||||
@Nonnull
|
||||
String getParamRule();
|
||||
@Nonnull
|
||||
String getDescription();
|
||||
|
||||
}
|
@ -1,297 +0,0 @@
|
||||
package cc.sukazyo.cono.morny.bot.command;
|
||||
|
||||
import cc.sukazyo.cono.morny.MornyCoeur;
|
||||
import cc.sukazyo.cono.morny.bot.event.OnUniMeowTrigger;
|
||||
import cc.sukazyo.cono.morny.daemon.MornyReport;
|
||||
import cc.sukazyo.cono.morny.data.MornyJrrp;
|
||||
import cc.sukazyo.cono.morny.data.TelegramStickers;
|
||||
import cc.sukazyo.cono.morny.util.tgapi.InputCommand;
|
||||
import cc.sukazyo.cono.morny.util.tgapi.formatting.TGToString;
|
||||
import com.pengrad.telegrambot.model.BotCommand;
|
||||
import com.pengrad.telegrambot.model.DeleteMyCommands;
|
||||
import com.pengrad.telegrambot.model.Update;
|
||||
import com.pengrad.telegrambot.model.request.ParseMode;
|
||||
import com.pengrad.telegrambot.request.SendMessage;
|
||||
import com.pengrad.telegrambot.request.SendSticker;
|
||||
import com.pengrad.telegrambot.request.SetMyCommands;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static cc.sukazyo.cono.morny.Log.logger;
|
||||
import static cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml;
|
||||
|
||||
public class MornyCommands {
|
||||
|
||||
private final Map<String, ISimpleCommand> commands = new LinkedHashMap<>();
|
||||
|
||||
private void pushCommandTo (@Nonnull String name, @Nonnull ISimpleCommand instance) {
|
||||
if (commands.containsKey(name)) {
|
||||
logger.warn(String.format("""
|
||||
Telegram command instance named "%s" already exists and will be override by another command instance
|
||||
- current: %s
|
||||
- new : %s""",
|
||||
name,
|
||||
commands.get(name).getClass().getName(),
|
||||
instance.getClass().getName()
|
||||
));
|
||||
}
|
||||
commands.put(name, instance);
|
||||
}
|
||||
|
||||
public void register (@Nonnull ISimpleCommand... list) {
|
||||
for (ISimpleCommand instance : list) {
|
||||
final String[] aliases = instance.getAliases();
|
||||
pushCommandTo(instance.getName(), instance);
|
||||
if (aliases!=null) for (String alias : aliases) pushCommandTo(alias, instance);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("NonAsciiCharacters")
|
||||
public MornyCommands () {
|
||||
|
||||
register(
|
||||
new ON(),
|
||||
new Hello(), /* new {@link HelloOnStart}, */
|
||||
MornyInformation$.MODULE$,
|
||||
GetUsernameAndId$.MODULE$,
|
||||
EventHack$.MODULE$,
|
||||
Nbnhhsh$.MODULE$,
|
||||
IP186Query.IP$.MODULE$,
|
||||
IP186Query.Whois$.MODULE$,
|
||||
Encryptor$.MODULE$,
|
||||
new SaveData(),
|
||||
MornyInfoOnHello$.MODULE$,
|
||||
new Version(),
|
||||
new MornyRuntime(),
|
||||
new Jrrp(),
|
||||
new Exit(), new ExitAlias()
|
||||
);
|
||||
|
||||
// 特殊的命令
|
||||
register(
|
||||
Testing$.MODULE$,
|
||||
DirectMsgClear$.MODULE$
|
||||
);
|
||||
|
||||
// 统一注册这些奇怪的东西&.&
|
||||
register(
|
||||
私わね$.MODULE$,
|
||||
喵呜.Progynova$.MODULE$
|
||||
);
|
||||
// special: 注册出于兼容使用的特别 event 的数据
|
||||
OnUniMeowTrigger.register(
|
||||
喵呜.抱抱$.MODULE$,
|
||||
喵呜.揉揉$.MODULE$,
|
||||
喵呜.蹭蹭$.MODULE$,
|
||||
喵呜.贴贴$.MODULE$
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
public boolean execute (@Nonnull InputCommand command, @Nonnull Update event) {
|
||||
if (commands.containsKey(command.getCommand())) {
|
||||
commands.get(command.getCommand()).execute(command, event);
|
||||
return true;
|
||||
}
|
||||
return nonCommandExecutable(event, command);
|
||||
}
|
||||
|
||||
public void automaticUpdateList () {
|
||||
BotCommand[] commandList = getCommandListTelegram();
|
||||
automaticRemoveList();
|
||||
MornyCoeur.extra().exec(new SetMyCommands(
|
||||
commandList
|
||||
));
|
||||
logger.info("automatic updated telegram command list :\n" + commandListToString(commandList));
|
||||
}
|
||||
|
||||
public void automaticRemoveList () {
|
||||
MornyCoeur.extra().exec(new DeleteMyCommands());
|
||||
logger.info("cleaned up command list.");
|
||||
}
|
||||
|
||||
private String commandListToString (@Nonnull BotCommand[] list) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (BotCommand signal : list) {
|
||||
builder.append(signal.command()).append(" - ").append(signal.description()).append("\n");
|
||||
}
|
||||
return builder.substring(0, builder.length()-1);
|
||||
}
|
||||
|
||||
public BotCommand[] getCommandListTelegram () {
|
||||
final List<BotCommand> telegramFormatListing = new ArrayList<>();
|
||||
commands.forEach((regKey, command) -> {
|
||||
if (command instanceof ITelegramCommand && regKey.equals(command.getName())) {
|
||||
telegramFormatListing.add(formatTelegramCommandListLine(
|
||||
command.getName(),
|
||||
((ITelegramCommand)command).getParamRule(),
|
||||
((ITelegramCommand)command).getDescription()
|
||||
));
|
||||
if (command.getAliases() != null) for (String alias : command.getAliases()) {
|
||||
telegramFormatListing.add(formatTelegramCommandListLine(alias, "", "↑"));
|
||||
}
|
||||
}
|
||||
});
|
||||
return telegramFormatListing.toArray(BotCommand[]::new);
|
||||
}
|
||||
|
||||
private BotCommand formatTelegramCommandListLine (@Nonnull String commandName, @Nonnull String paramRule, @Nonnull String intro) {
|
||||
return new BotCommand(commandName, paramRule.isEmpty() ? (intro) : (paramRule+" - "+intro));
|
||||
}
|
||||
|
||||
private boolean nonCommandExecutable (Update event, InputCommand command) {
|
||||
if (command.getTarget() == null) return false; // 无法解析的命令,转交事件链后代处理
|
||||
else { // 无法解析的显式命令格式,报错找不到命令
|
||||
MornyCoeur.extra().exec(new SendSticker(
|
||||
event.message().chat().id(),
|
||||
TelegramStickers.ID_404
|
||||
).replyToMessageId(event.message().messageId())
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// /// /// /// /// /// /// /// ///
|
||||
///
|
||||
/// Old Simple Command Block
|
||||
///
|
||||
|
||||
private static class ON implements ITelegramCommand {
|
||||
@Nonnull @Override public String getName () { return "o"; }
|
||||
@Nullable
|
||||
@Override public String[] getAliases () { return null; }
|
||||
@Nonnull @Override public String getParamRule () { return ""; }
|
||||
@Nonnull @Override public String getDescription () { return "检查是否在线"; }
|
||||
@Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { onCommandOnExec(event); }
|
||||
}
|
||||
private static void onCommandOnExec (@Nonnull Update event) {
|
||||
MornyCoeur.extra().exec(new SendSticker(
|
||||
event.message().chat().id(),
|
||||
TelegramStickers.ID_ONLINE_STATUS_RETURN
|
||||
).replyToMessageId(event.message().messageId())
|
||||
);
|
||||
}
|
||||
|
||||
private static class Hello implements ITelegramCommand {
|
||||
@Nonnull @Override public String getName () { return "hello"; }
|
||||
@Nullable @Override public String[] getAliases () { return new String[]{"hi"}; }
|
||||
@Nonnull @Override public String getParamRule () { return ""; }
|
||||
@Nonnull @Override public String getDescription () { return "打招呼"; }
|
||||
@Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { onCommandHelloExec(event); }
|
||||
}
|
||||
/**
|
||||
* {@link Hello} on special command /start
|
||||
* Deprecated due to new {@link MornyInfoOnHello}
|
||||
*/
|
||||
@Deprecated @SuppressWarnings("unused")
|
||||
private static class HelloOnStart implements ISimpleCommand { @Nonnull @Override public String getName () { return "start"; }@Nullable @Override public String[] getAliases () { return new String[0]; }@Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { onCommandHelloExec(event); }}
|
||||
private static void onCommandHelloExec (@Nonnull Update event) {
|
||||
MornyCoeur.extra().exec(new SendSticker(
|
||||
event.message().chat().id(),
|
||||
TelegramStickers.ID_HELLO
|
||||
).replyToMessageId(event.message().messageId())
|
||||
);
|
||||
}
|
||||
|
||||
private static class Exit implements ITelegramCommand {
|
||||
@Nonnull @Override public String getName () { return "exit"; }
|
||||
@Nullable @Override public String[] getAliases () { return new String[0]; }
|
||||
@Nonnull @Override public String getParamRule () { return ""; }
|
||||
@Nonnull @Override public String getDescription () { return "关闭 Bot (仅可信成员)"; }
|
||||
@Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { onCommandExitExec(event); }
|
||||
}
|
||||
private static class ExitAlias implements ISimpleCommand {
|
||||
@Nonnull @Override public String getName () { return "quit"; }
|
||||
@Nullable @Override public String[] getAliases () { return new String[]{"stop"}; }
|
||||
@Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { onCommandExitExec(event); }
|
||||
}
|
||||
private static void onCommandExitExec (@Nonnull Update event) {
|
||||
if (MornyCoeur.trustedInstance().isTrusted(event.message().from().id())) {
|
||||
MornyCoeur.extra().exec(new SendSticker(
|
||||
event.message().chat().id(),
|
||||
TelegramStickers.ID_EXIT
|
||||
).replyToMessageId(event.message().messageId())
|
||||
);
|
||||
logger.info("Morny exited by user " + TGToString.as(event.message().from()).toStringLogTag());
|
||||
MornyCoeur.exit(0, event.message().from());
|
||||
} else {
|
||||
MornyCoeur.extra().exec(new SendSticker(
|
||||
event.message().chat().id(),
|
||||
TelegramStickers.ID_403
|
||||
).replyToMessageId(event.message().messageId())
|
||||
);
|
||||
logger.info("403 exited tag from user " + TGToString.as(event.message().from()).toStringLogTag());
|
||||
MornyReport.unauthenticatedAction("/exit", event.message().from());
|
||||
}
|
||||
}
|
||||
|
||||
private static class Version implements ISimpleCommand {
|
||||
@Nonnull @Override public String getName () { return "version"; }
|
||||
@Nullable @Override public String[] getAliases () { return null; }
|
||||
@Nonnull @Deprecated public String getParamRule () { return ""; }
|
||||
@Nonnull @Deprecated public String getDescription () { return "检查 Bot 版本信息"; }
|
||||
@Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { MornyInformation.echoVersion(event); }
|
||||
}
|
||||
|
||||
private static class MornyRuntime implements ISimpleCommand {
|
||||
@Nonnull @Override public String getName () { return "runtime"; }
|
||||
@Nullable @Override public String[] getAliases () { return null; }
|
||||
@Nonnull @Deprecated public String getParamRule () { return ""; }
|
||||
@Nonnull @Deprecated public String getDescription () { return "获取 Bot 运行时信息(包括版本号)"; }
|
||||
@Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { MornyInformation.echoRuntime(event); }
|
||||
}
|
||||
|
||||
private static class Jrrp implements ITelegramCommand {
|
||||
@Nonnull @Override public String getName () { return "jrrp"; }
|
||||
@Nullable @Override public String[] getAliases () { return null; }
|
||||
@Nonnull @Override public String getParamRule () { return ""; }
|
||||
@Nonnull @Override public String getDescription () { return "获取 (假的) jrrp"; }
|
||||
@Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { onCommandJrrpExec(event); }
|
||||
}
|
||||
private static void onCommandJrrpExec (Update event) {
|
||||
final double jrrp = MornyJrrp.getJrrpFromTelegramUser(event.message().from(), System.currentTimeMillis());
|
||||
final String endChar = jrrp>70 ? "!" : jrrp>30 ? ";" : "...";
|
||||
MornyCoeur.extra().exec(new SendMessage(
|
||||
event.message().chat().id(),
|
||||
String.format(
|
||||
"%s 在(utc的)今天的运气指数是———— <code>%.2f%%</code> %s",
|
||||
TGToString.as(event.message().from()).fullnameRefHtml(),
|
||||
jrrp, escapeHtml(endChar)
|
||||
)
|
||||
).replyToMessageId(event.message().messageId()).parseMode(ParseMode.HTML));
|
||||
}
|
||||
|
||||
private static class SaveData implements ITelegramCommand {
|
||||
@Nonnull @Override public String getName () { return "save"; }
|
||||
@Nullable @Override public String[] getAliases () { return null; }
|
||||
@Nonnull @Override public String getParamRule () { return ""; }
|
||||
@Nonnull @Override public String getDescription () { return "保存缓存数据到文件(仅可信成员)"; }
|
||||
@Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) { onSaveDataExec(event); }
|
||||
}
|
||||
/**
|
||||
* @since 0.4.3.0
|
||||
*/
|
||||
private static void onSaveDataExec (Update event) {
|
||||
if (MornyCoeur.trustedInstance().isTrusted(event.message().from().id())) {
|
||||
logger.info("called save from command by " + TGToString.as(event.message().from()).toStringLogTag());
|
||||
MornyCoeur.callSaveData();
|
||||
MornyCoeur.extra().exec(new SendSticker(
|
||||
event.message().chat().id(),
|
||||
TelegramStickers.ID_SAVED
|
||||
).replyToMessageId(event.message().messageId())
|
||||
);
|
||||
} else {
|
||||
MornyCoeur.extra().exec(new SendSticker(
|
||||
event.message().chat().id(),
|
||||
TelegramStickers.ID_403
|
||||
).replyToMessageId(event.message().messageId())
|
||||
);
|
||||
logger.info("403 call save tag from user " + TGToString.as(event.message().from()).toStringLogTag());
|
||||
MornyReport.unauthenticatedAction("/save", event.message().from());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
package cc.sukazyo.cono.morny.bot.event;
|
||||
|
||||
import cc.sukazyo.cono.morny.bot.api.EventListenerManager;
|
||||
import cc.sukazyo.cono.morny.bot.api.InlineQueryUnit;
|
||||
|
||||
public class EventListeners {
|
||||
|
||||
public static final OnTelegramCommand COMMANDS_LISTENER = new OnTelegramCommand();
|
||||
// public static final OnActivityRecord ACTIVITY_RECORDER = new OnActivityRecord();
|
||||
public static final OnUpdateTimestampOffsetLock UPDATE_TIMESTAMP_OFFSET_LOCK = new OnUpdateTimestampOffsetLock();
|
||||
public static final OnEventHackHandle EVENT_HACK_HANDLE = new OnEventHackHandle();
|
||||
// static final OnKuohuanhuanNeedSleep KUOHUANHUAN_NEED_SLEEP = new OnKuohuanhuanNeedSleep();
|
||||
public static final OnCallMsgSend CALL_MSG_SEND = new OnCallMsgSend();
|
||||
public static final OnMedicationNotifyApply MEDICATION_NOTIFY_APPLY = new OnMedicationNotifyApply();
|
||||
public static final OnRandomlyTriggered RANDOMLY_TRIGGERED = new OnRandomlyTriggered();
|
||||
public static final OnUniMeowTrigger UNI_MEOW_TRIGGER = new OnUniMeowTrigger();
|
||||
public static final OnQuestionMarkReply QUESTION_MARK_REPLY = new OnQuestionMarkReply();
|
||||
|
||||
public static void registerAllListeners () {
|
||||
EventListenerManager.addListener(
|
||||
// ACTIVITY_RECORDER,
|
||||
UPDATE_TIMESTAMP_OFFSET_LOCK,
|
||||
/* write functional event behind here */
|
||||
// KUOHUANHUAN_NEED_SLEEP,
|
||||
COMMANDS_LISTENER,
|
||||
UNI_MEOW_TRIGGER,
|
||||
RANDOMLY_TRIGGERED,
|
||||
OnUserRandom$.MODULE$,
|
||||
QUESTION_MARK_REPLY,
|
||||
OnUserSlashAction$.MODULE$,
|
||||
OnInlineQuery$.MODULE$,
|
||||
OnCallMe$.MODULE$,
|
||||
CALL_MSG_SEND,
|
||||
MEDICATION_NOTIFY_APPLY,
|
||||
EVENT_HACK_HANDLE
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -8,7 +8,7 @@ import com.pengrad.telegrambot.model.Update;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
@Deprecated
|
||||
public class OnActivityRecord extends EventListener {
|
||||
public class OnActivityRecord implements EventListener {
|
||||
|
||||
@Override
|
||||
public boolean onMessage (@Nonnull Update update) {
|
||||
@ -22,7 +22,7 @@ public class OnActivityRecord extends EventListener {
|
||||
(long)update.message().date() * 1000
|
||||
);
|
||||
}
|
||||
return super.onMessage(update);
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,222 +0,0 @@
|
||||
package cc.sukazyo.cono.morny.bot.event;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.pengrad.telegrambot.model.Chat;
|
||||
import com.pengrad.telegrambot.model.Message;
|
||||
import com.pengrad.telegrambot.model.MessageEntity;
|
||||
import com.pengrad.telegrambot.model.Update;
|
||||
import com.pengrad.telegrambot.model.request.ParseMode;
|
||||
import com.pengrad.telegrambot.request.GetChat;
|
||||
import com.pengrad.telegrambot.request.SendMessage;
|
||||
import com.pengrad.telegrambot.request.SendSticker;
|
||||
|
||||
import cc.sukazyo.cono.morny.MornyCoeur;
|
||||
import cc.sukazyo.cono.morny.bot.api.EventListener;
|
||||
import cc.sukazyo.cono.morny.data.TelegramStickers;
|
||||
import com.pengrad.telegrambot.response.GetChatResponse;
|
||||
import com.pengrad.telegrambot.response.SendResponse;
|
||||
|
||||
import static cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml;
|
||||
|
||||
|
||||
public class OnCallMsgSend extends EventListener {
|
||||
|
||||
private static final Pattern REGEX_MSG_SENDREQ_DATA_HEAD = Pattern.compile("^\\*msg(-?\\d+)(\\*\\S+)?(?:\\n([\\s\\S]+))?$");
|
||||
|
||||
private record MessageToSend (
|
||||
@Nullable String message,
|
||||
@Nullable MessageEntity[] entities,
|
||||
@Nullable ParseMode parseMode,
|
||||
long targetId
|
||||
) { }
|
||||
|
||||
@Override
|
||||
public boolean onMessage(@Nonnull Update update) {
|
||||
|
||||
// 执行体检查
|
||||
if (update.message().chat().type() != Chat.Type.Private) return false;
|
||||
if (update.message().text() == null) return false;
|
||||
if (!update.message().text().startsWith("*msg")) return false;
|
||||
|
||||
// 权限检查
|
||||
if (!MornyCoeur.trustedInstance().isTrusted(update.message().from().id())) {
|
||||
MornyCoeur.extra().exec(new SendSticker(
|
||||
update.message().chat().id(),
|
||||
TelegramStickers.ID_403
|
||||
).replyToMessageId(update.message().messageId()));
|
||||
return true;
|
||||
}
|
||||
|
||||
Message msgsendReqRaw; // 用户书写的发送请求原文
|
||||
MessageToSend msgsendReqBody; // 解析后的发送请求实例
|
||||
|
||||
// *msgsend 发送标识
|
||||
// 处理发送要求
|
||||
if (update.message().text().equals("*msgsend")) {
|
||||
// 发送体处理
|
||||
if (update.message().replyToMessage() == null) return answer404(update);
|
||||
msgsendReqBody = parseRequest(update.message().replyToMessage());
|
||||
if (msgsendReqBody == null || msgsendReqBody.message == null) return answer404(update);
|
||||
// 执行发送任务
|
||||
SendResponse sendResponse = MornyCoeur.getAccount().execute(parseMessageToSend(msgsendReqBody));
|
||||
if (!sendResponse.isOk()) { // 发送失败
|
||||
MornyCoeur.extra().exec(new SendMessage(
|
||||
update.message().chat().id(),
|
||||
String.format("""
|
||||
<b><u>%d</u> FAILED</b>
|
||||
<code>%s</code>""",
|
||||
sendResponse.errorCode(),
|
||||
sendResponse.description()
|
||||
)
|
||||
).replyToMessageId(update.message().messageId()).parseMode(ParseMode.HTML));
|
||||
} else { // 发送成功信号
|
||||
MornyCoeur.extra().exec(new SendSticker(
|
||||
update.message().chat().id(),
|
||||
TelegramStickers.ID_SENT
|
||||
).replyToMessageId(update.message().messageId()));
|
||||
}
|
||||
return true;
|
||||
// 发送完成/失败 - 事件结束
|
||||
}
|
||||
|
||||
// *msg 检查标识
|
||||
if (update.message().text().equals("*msg")) { // 处理对曾经的原文的检查
|
||||
if (update.message().replyToMessage() == null) {
|
||||
return answer404(update);
|
||||
}
|
||||
msgsendReqRaw = update.message().replyToMessage();
|
||||
} else if (update.message().text().startsWith("*msg")) { // 对接受到的原文进行检查
|
||||
msgsendReqRaw = update.message();
|
||||
} else {
|
||||
return answer404(update); // 未定义的动作
|
||||
}
|
||||
|
||||
// 对发送请求的用户原文进行解析
|
||||
msgsendReqBody = parseRequest(msgsendReqRaw);
|
||||
if (msgsendReqBody == null) {
|
||||
return answer404(update);
|
||||
}
|
||||
|
||||
// 输出发送目标信息
|
||||
GetChatResponse targetChatReq = MornyCoeur.getAccount().execute(new GetChat(msgsendReqBody.targetId()));
|
||||
if (!targetChatReq.isOk()) {
|
||||
MornyCoeur.extra().exec(new SendMessage(
|
||||
update.message().chat().id(),
|
||||
String.format("""
|
||||
<b><u>%d</u> FAILED</b>
|
||||
<code>%s</code>""",
|
||||
targetChatReq.errorCode(),
|
||||
targetChatReq.description()
|
||||
)
|
||||
).replyToMessageId(update.message().messageId()).parseMode(ParseMode.HTML));
|
||||
} else {
|
||||
MornyCoeur.extra().exec(new SendMessage(
|
||||
update.message().chat().id(),
|
||||
targetChatReq.chat().type() == Chat.Type.Private ? (
|
||||
String.format("""
|
||||
<i><u>%d</u>@%s</i>
|
||||
🔒 <b>%s</b> %s""",
|
||||
msgsendReqBody.targetId(),
|
||||
escapeHtml(targetChatReq.chat().type().name()),
|
||||
escapeHtml(targetChatReq.chat().firstName()+(targetChatReq.chat().lastName()==null?"":" "+targetChatReq.chat().lastName())),
|
||||
targetChatReq.chat().username()==null?
|
||||
String.format("<a href='tg://user?id=%d'>@@</a>", targetChatReq.chat().id()):
|
||||
(escapeHtml("@"+targetChatReq.chat().username()))
|
||||
)
|
||||
) : (
|
||||
String.format("""
|
||||
<i><u>%d</u>@%s</i>:::
|
||||
%s <b>%s</b>%s""",
|
||||
msgsendReqBody.targetId(),
|
||||
escapeHtml(targetChatReq.chat().type().name()),
|
||||
switch (targetChatReq.chat().type()) {
|
||||
case group -> "💭";
|
||||
case channel -> "📢";
|
||||
case supergroup -> "💬";
|
||||
default -> "⭕️";
|
||||
},
|
||||
escapeHtml(targetChatReq.chat().title()),
|
||||
targetChatReq.chat().username() != null?String.format(
|
||||
" @%s", escapeHtml(targetChatReq.chat().username())
|
||||
):""
|
||||
)
|
||||
)
|
||||
).replyToMessageId(update.message().messageId()).parseMode(ParseMode.HTML));
|
||||
}
|
||||
// 发送文本测试
|
||||
if (msgsendReqBody.message == null) return true;
|
||||
final SendResponse testSendResp = MornyCoeur.getAccount().execute(
|
||||
parseMessageToSend(msgsendReqBody, update.message().chat().id()).replyToMessageId(update.message().messageId())
|
||||
);
|
||||
if (!testSendResp.isOk()) {
|
||||
MornyCoeur.extra().exec(new SendMessage(
|
||||
update.message().chat().id(),
|
||||
String.format("""
|
||||
<b><u>%d</u> FAILED</b>
|
||||
<code>%s</code>""",
|
||||
testSendResp.errorCode(),
|
||||
testSendResp.description()
|
||||
)
|
||||
).replyToMessageId(update.message().messageId()).parseMode(ParseMode.HTML));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static MessageToSend parseRequest (@Nonnull Message requestBody) {
|
||||
|
||||
final Matcher matcher = REGEX_MSG_SENDREQ_DATA_HEAD.matcher(requestBody.text());
|
||||
if (matcher.matches()) {
|
||||
long targetId = Long.parseLong(matcher.group(1));
|
||||
ParseMode parseMode = matcher.group(2) == null ? null : switch (matcher.group(2)) {
|
||||
case "*markdown", "*md", "*m↓" -> ParseMode.MarkdownV2;
|
||||
case "*md1" -> ParseMode.Markdown;
|
||||
case "*html" -> ParseMode.HTML;
|
||||
default -> null;
|
||||
};
|
||||
final int offset = "*msg".length()+matcher.group(1).length()+(matcher.group(2)==null?0:matcher.group(2).length())+1;
|
||||
final ArrayList<MessageEntity> entities = new ArrayList<>();
|
||||
if (requestBody.entities() != null) for (MessageEntity entity : requestBody.entities()) {
|
||||
final MessageEntity parsed = new MessageEntity(entity.type(), entity.offset() - offset, entity.length());
|
||||
if (entity.url() != null) parsed.url(entity.url());
|
||||
if (entity.user() != null) parsed.user(entity.user());
|
||||
if (entity.language() != null) parsed.language(entity.language());
|
||||
entities.add(parsed);
|
||||
}
|
||||
return new MessageToSend(matcher.group(3), entities.toArray(MessageEntity[]::new), parseMode, targetId);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private static SendMessage parseMessageToSend (@Nonnull MessageToSend body) {
|
||||
return parseMessageToSend(body, body.targetId);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private static SendMessage parseMessageToSend (@Nonnull MessageToSend body, long targetId) {
|
||||
SendMessage sendingBody = new SendMessage(targetId, body.message);
|
||||
if (body.entities != null) sendingBody.entities(body.entities);
|
||||
if (body.parseMode != null) sendingBody.parseMode(body.parseMode);
|
||||
return sendingBody;
|
||||
}
|
||||
|
||||
private static boolean answer404 (@Nonnull Update update) {
|
||||
MornyCoeur.extra().exec(new SendSticker(
|
||||
update.message().chat().id(),
|
||||
TelegramStickers.ID_404
|
||||
).replyToMessageId(update.message().messageId()));
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -1,145 +0,0 @@
|
||||
package cc.sukazyo.cono.morny.bot.event;
|
||||
|
||||
import cc.sukazyo.cono.morny.MornyCoeur;
|
||||
import cc.sukazyo.cono.morny.bot.api.EventListener;
|
||||
import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape;
|
||||
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.pengrad.telegrambot.model.Update;
|
||||
import com.pengrad.telegrambot.model.request.ParseMode;
|
||||
import com.pengrad.telegrambot.request.SendMessage;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static cc.sukazyo.cono.morny.Log.logger;
|
||||
|
||||
/**
|
||||
* 事件劫持与序列化工具.
|
||||
* @since 0.4.2.0
|
||||
*/
|
||||
public class OnEventHackHandle extends EventListener {
|
||||
|
||||
/** 事件劫持请求列表 */
|
||||
private static final Map<String, Hacker> hackers = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 触发事件劫持的限定条件.
|
||||
* @since 0.4.2.0
|
||||
*/
|
||||
public enum HackType {
|
||||
/** 只有相同用户发起的事件才会被触发 */
|
||||
USER,
|
||||
/** 只有相同群组内发生的事件才会触发 */
|
||||
GROUP,
|
||||
/** 任何事件都可以触发 */
|
||||
ANY
|
||||
}
|
||||
|
||||
public record Hacker(long fromChatId, long fromMessageId) {
|
||||
@Override public String toString() {
|
||||
return fromChatId + "/" + fromMessageId;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.4.2.0
|
||||
*/
|
||||
public static void registerHack(long fromMessageId, long fromUserId, long fromChatId, @Nonnull HackType type) {
|
||||
String rec = null;
|
||||
switch (type) {
|
||||
case USER -> rec = String.format("((%d))", fromUserId);
|
||||
case GROUP -> rec = String.format("{{%d}}", fromChatId);
|
||||
case ANY -> rec = "[[]]";
|
||||
}
|
||||
hackers.put(rec, new Hacker(fromChatId, fromMessageId));
|
||||
logger.debug("add hacker track " + rec);
|
||||
}
|
||||
|
||||
private boolean onEventHacked (Update update, long chatId, long fromUser) {
|
||||
logger.debug(String.format("got event signed {{%d}}((%d))", chatId, fromUser));
|
||||
Hacker x;
|
||||
x = hackers.remove(String.format("((%d))", fromUser));
|
||||
if (x == null) x = hackers.remove(String.format("{{%d}}", chatId));
|
||||
if (x == null) x = hackers.remove("[[]]");
|
||||
if (x == null) return false;
|
||||
logger.debug("hacked event by " + x);
|
||||
MornyCoeur.extra().exec(new SendMessage(x.fromChatId, String.format(
|
||||
"<code>%s</code>",
|
||||
MsgEscape.escapeHtml(new GsonBuilder().setPrettyPrinting().create().toJson(update))
|
||||
)).parseMode(ParseMode.HTML).replyToMessageId((int)x.fromMessageId));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMessage (@Nonnull Update update) {
|
||||
return onEventHacked(update, update.message().chat().id(), update.message().from().id());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onEditedMessage (@Nonnull Update update) {
|
||||
return onEventHacked(update, update.editedMessage().chat().id(), update.editedMessage().from().id());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onChannelPost (@Nonnull Update update) {
|
||||
return onEventHacked(update, update.channelPost().chat().id(), update.channelPost().chat().id());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onEditedChannelPost (@Nonnull Update update) {
|
||||
return onEventHacked(update, update.editedChannelPost().chat().id(), update.editedChannelPost().chat().id());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInlineQuery (@Nonnull Update update) {
|
||||
return onEventHacked(update, 0, update.inlineQuery().from().id());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onChosenInlineResult (@Nonnull Update update) {
|
||||
return onEventHacked(update, 0, update.chosenInlineResult().from().id());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCallbackQuery (@Nonnull Update update) {
|
||||
return onEventHacked(update, 0, update.callbackQuery().from().id());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onShippingQuery (@Nonnull Update update) {
|
||||
return onEventHacked(update, 0, update.shippingQuery().from().id());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreCheckoutQuery (@Nonnull Update update) {
|
||||
return onEventHacked(update, 0, update.preCheckoutQuery().from().id());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPoll (@Nonnull Update update) {
|
||||
return onEventHacked(update, 0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPollAnswer (@Nonnull Update update) {
|
||||
return onEventHacked(update, 0, update.pollAnswer().user().id());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMyChatMemberUpdated (@Nonnull Update update) {
|
||||
return onEventHacked(update, update.myChatMember().chat().id(), update.myChatMember().from().id());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onChatMemberUpdated (@Nonnull Update update) {
|
||||
return onEventHacked(update, update.chatMember().chat().id(), update.chatMember().from().id());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onChatJoinRequest (@Nonnull Update update) {
|
||||
return onEventHacked(update, update.chatJoinRequest().chat().id(), update.chatJoinRequest().from().id());
|
||||
}
|
||||
|
||||
}
|
@ -11,7 +11,7 @@ import java.util.GregorianCalendar;
|
||||
import java.util.Locale;
|
||||
|
||||
@Deprecated
|
||||
public class OnKuohuanhuanNeedSleep extends EventListener {
|
||||
public class OnKuohuanhuanNeedSleep implements EventListener {
|
||||
|
||||
@Override
|
||||
public boolean onMessage (@Nonnull Update update) {
|
||||
|
@ -1,29 +0,0 @@
|
||||
package cc.sukazyo.cono.morny.bot.event;
|
||||
|
||||
import cc.sukazyo.cono.morny.MornyCoeur;
|
||||
import cc.sukazyo.cono.morny.bot.api.EventListener;
|
||||
import cc.sukazyo.cono.morny.daemon.MornyDaemons;
|
||||
import com.pengrad.telegrambot.model.Message;
|
||||
import com.pengrad.telegrambot.model.Update;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public class OnMedicationNotifyApply extends EventListener {
|
||||
|
||||
@Override
|
||||
public boolean onEditedChannelPost (@Nonnull Update update) {
|
||||
return editedMessageProcess(update.editedChannelPost());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onEditedMessage (@Nonnull Update update) {
|
||||
return editedMessageProcess(update.editedMessage());
|
||||
}
|
||||
|
||||
private boolean editedMessageProcess (Message edited) {
|
||||
if (edited.chat().id() != MornyCoeur.config().medicationNotifyToChat) return false;
|
||||
MornyDaemons.medicationTimerInstance.refreshNotificationWrite(edited);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
package cc.sukazyo.cono.morny.bot.event;
|
||||
|
||||
import cc.sukazyo.cono.morny.MornyCoeur;
|
||||
import cc.sukazyo.cono.morny.bot.api.EventListener;
|
||||
import com.pengrad.telegrambot.model.Update;
|
||||
import com.pengrad.telegrambot.request.SendMessage;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.Set;
|
||||
|
||||
import static cc.sukazyo.cono.morny.util.CommonRandom.probabilityTrue;
|
||||
|
||||
public class OnQuestionMarkReply extends EventListener {
|
||||
|
||||
/**
|
||||
* 一个 unicode 的问号字符列表. 不仅有半角全角问号,也包含了变体问号,和叹号结合的问好以及 uni-emoji 问号。
|
||||
* @since 1.0.0-RC3.2
|
||||
*/
|
||||
public static final Set<Character> QUESTION_MARKS = Set.of('?', '?', '¿', '⁈', '⁇', '‽', '❔', '❓');
|
||||
|
||||
@Override
|
||||
public boolean onMessage (@Nonnull Update update) {
|
||||
|
||||
if (update.message().text() == null) return false;
|
||||
|
||||
if (!probabilityTrue(8)) return false;
|
||||
for (char c : update.message().text().toCharArray()) {
|
||||
if (!QUESTION_MARKS.contains(c)) return false;
|
||||
}
|
||||
|
||||
MornyCoeur.extra().exec(new SendMessage(
|
||||
update.message().chat().id(), update.message().text()
|
||||
).replyToMessageId(update.message().messageId()));
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -2,7 +2,8 @@ package cc.sukazyo.cono.morny.bot.event;
|
||||
|
||||
import cc.sukazyo.cono.morny.bot.api.EventListener;
|
||||
|
||||
public class OnRandomlyTriggered extends EventListener {
|
||||
@Deprecated
|
||||
public class OnRandomlyTriggered implements EventListener {
|
||||
|
||||
// /**
|
||||
// * function CODE_IK0XA1
|
||||
|
@ -1,30 +0,0 @@
|
||||
package cc.sukazyo.cono.morny.bot.event;
|
||||
|
||||
import cc.sukazyo.cono.morny.MornyCoeur;
|
||||
import cc.sukazyo.cono.morny.bot.api.EventListener;
|
||||
import cc.sukazyo.cono.morny.util.tgapi.InputCommand;
|
||||
|
||||
import com.pengrad.telegrambot.model.Update;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import static cc.sukazyo.cono.morny.Log.logger;
|
||||
|
||||
public class OnTelegramCommand extends EventListener {
|
||||
|
||||
@Override
|
||||
public boolean onMessage (@Nonnull Update event) {
|
||||
if (event.message().text() == null || !event.message().text().startsWith("/") || event.message().text().startsWith("/ ")) {
|
||||
logger.debug("not command");
|
||||
return false; // 检测到非(命令格式)文本,忽略掉命令处理
|
||||
}
|
||||
final InputCommand command = new InputCommand(event.message().text().substring(1));
|
||||
if (!command.getCommand().matches("^\\w+$")) { logger.debug("not command");return false; }
|
||||
logger.debug("is command");
|
||||
if (command.getTarget() != null && !MornyCoeur.getUsername().equals(command.getTarget())) {
|
||||
return true; // 检测到命令并非针对 morny,退出整个事件处理链
|
||||
}
|
||||
return MornyCoeur.commandManager().execute(command, event); // 转交命令管理器执行命令
|
||||
}
|
||||
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
package cc.sukazyo.cono.morny.bot.event;
|
||||
|
||||
import cc.sukazyo.cono.morny.bot.api.EventListener;
|
||||
import cc.sukazyo.cono.morny.bot.command.ISimpleCommand;
|
||||
import cc.sukazyo.cono.morny.util.tgapi.InputCommand;
|
||||
import com.pengrad.telegrambot.model.Update;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class OnUniMeowTrigger extends EventListener {
|
||||
|
||||
private static final Map<String, ISimpleCommand> 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();
|
||||
}
|
||||
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
package cc.sukazyo.cono.morny.bot.event;
|
||||
|
||||
import cc.sukazyo.cono.morny.MornyCoeur;
|
||||
import cc.sukazyo.cono.morny.bot.api.EventListener;
|
||||
import com.pengrad.telegrambot.model.Update;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* 阻止 {@link cc.sukazyo.cono.morny.MornyConfig#eventOutdatedTimestamp 指定时间} 之前的事件处理.
|
||||
* <p>
|
||||
* 只支持以下事件
|
||||
* <ul>
|
||||
* <li>{@link EventListener#onMessage(Update) 收到消息}</li>
|
||||
* <li>{@link EventListener#onEditedMessage(Update) 消息被更新}</li>
|
||||
* <li>{@link EventListener#onChannelPost(Update) 收到频道消息}</li>
|
||||
* <li>{@link EventListener#onEditedChannelPost(Update) 频道消息被更新}</li>
|
||||
* </ul>
|
||||
* @see #isOutdated 时间判断
|
||||
*/
|
||||
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.config().eventOutdatedTimestamp/1000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMessage (@Nonnull Update update) {
|
||||
return isOutdated(update.message().date());
|
||||
}
|
||||
|
||||
/** @since 0.4.2.6 */
|
||||
@Override
|
||||
public boolean onEditedMessage (@Nonnull Update update) {
|
||||
return isOutdated(update.editedMessage().editDate());
|
||||
}
|
||||
|
||||
/** @since 0.4.2.6 */
|
||||
@Override
|
||||
public boolean onChannelPost (@Nonnull Update update) {
|
||||
return isOutdated(update.channelPost().date());
|
||||
}
|
||||
|
||||
/** @since 0.4.2.6 */
|
||||
@Override
|
||||
public boolean onEditedChannelPost (@Nonnull Update update) {
|
||||
return isOutdated(update.editedChannelPost().editDate());
|
||||
}
|
||||
|
||||
}
|
@ -37,7 +37,7 @@ public class MornyReport {
|
||||
}
|
||||
}
|
||||
|
||||
public static void exception (@Nonnull Exception e, @Nullable String description) {
|
||||
public static void exception (@Nonnull Throwable e, @Nullable String description) {
|
||||
if (unsupported()) return;
|
||||
executeReport(new SendMessage(
|
||||
MornyCoeur.config().reportToChat,
|
||||
|
@ -1,46 +0,0 @@
|
||||
package cc.sukazyo.cono.morny.data;
|
||||
|
||||
import cc.sukazyo.cono.morny.util.CommonConvert;
|
||||
import cc.sukazyo.cono.morny.util.CommonEncrypt;
|
||||
import com.pengrad.telegrambot.model.User;
|
||||
|
||||
/**
|
||||
* Morny 的 jrrp 运算类.
|
||||
*
|
||||
* @see #getJrrpFromTelegramUser(User,long)
|
||||
* @see #calcJrrpXmomi(long,long)
|
||||
* @since 0.4.2.9
|
||||
*/
|
||||
public class MornyJrrp {
|
||||
|
||||
/**
|
||||
* 通过 telegram 用户和时间戳作为参数获取 jrrp.
|
||||
*
|
||||
* @see #calcJrrpXmomi 当前版本的实现算法 {@code Xmomi}
|
||||
* @since 0.4.2.9
|
||||
* @param user telegram 用户
|
||||
* @param timestamp 时间戳
|
||||
* @return 通过当前版本的算法计算出的用户 jrrp 值,取值为 {@code [0.00, 100.00]}
|
||||
*/
|
||||
public static double getJrrpFromTelegramUser (User user, long timestamp) {
|
||||
return calcJrrpXmomi(user.id(), timestamp / (1000 * 60 * 60 * 24)) * 100.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code Xmomi} 版本的 jrrp 算法.
|
||||
* <p>
|
||||
* 算法规则为,将用户id与日期戳链接为 <u><code>uid@daystamp</code></u> 这样的字符串,
|
||||
* 然后通过 MD5 计算出字符串的哈希值,取哈希值前4个字节,将其作为16进制数值表示法转换为取值为 {@code [0x0000, 0xffff]} 的数值,
|
||||
* 得到的数值除以区间最大值 {@code 0xffff} 即可得到一个分布在 {@code [0.0, 1.0]} 之间的分布值,
|
||||
* 这个分布值乘以 {@code 100.0},即为计算得到的 jrrp 数值。
|
||||
*
|
||||
* @since 0.4.2.9
|
||||
* @param userId telegram 用户 uid
|
||||
* @param dayStamp unix 时间戳转换为日期单位后的数值. 数值应该在转换前转换时区
|
||||
* @return 算法得到的 jrrp 值,取值为 {@code [0.00. 100.00]}
|
||||
*/
|
||||
public static double calcJrrpXmomi (long userId, long dayStamp) {
|
||||
return (double)Long.parseLong(CommonConvert.byteArrayToHex(CommonEncrypt.hashMd5(userId + "@" + dayStamp)).substring(0, 4), 16) / (double)0xffff;
|
||||
}
|
||||
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
package cc.sukazyo.cono.morny.data;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import cc.sukazyo.cono.morny.util.OkHttpPublic.MediaTypes;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.ResponseBody;
|
||||
|
||||
public class NbnhhshQuery {
|
||||
|
||||
public static class Word {
|
||||
public String name;
|
||||
public String[] trans;
|
||||
public String[] inputting;
|
||||
}
|
||||
|
||||
public static class GuessResult {
|
||||
public Word[] words;
|
||||
}
|
||||
|
||||
public record GuessReq (String text) {}
|
||||
|
||||
public static final String API_URL = "https://lab.magiconch.com/api/nbnhhsh/";
|
||||
public static final String API_GUESS_METHOD = "guess/";
|
||||
|
||||
private static final OkHttpClient httpClient = new OkHttpClient();
|
||||
|
||||
public static GuessResult sendGuess (String text) throws IOException {
|
||||
final String reqJsonText = new Gson().toJson(new GuessReq(text));
|
||||
Request request = new Request.Builder()
|
||||
.url(API_URL + API_GUESS_METHOD)
|
||||
.post(RequestBody.create(reqJsonText, MediaTypes.JSON))
|
||||
.build();
|
||||
try (Response response = httpClient.newCall(request).execute()) {
|
||||
final ResponseBody body = response.body();
|
||||
if (body == null) throw new IOException("Null body.");
|
||||
final String x = "{ \"words\": " + body.string() + " }";
|
||||
return new Gson().fromJson(x, GuessResult.class);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,10 +1,15 @@
|
||||
package cc.sukazyo.cono.morny.util.tgapi.formatting;
|
||||
|
||||
import com.pengrad.telegrambot.model.Chat;
|
||||
import com.pengrad.telegrambot.model.Message;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class TGToStringFromChat {
|
||||
|
||||
|
||||
public static final long MASK_BOTAPI_ID = -1000000000000L;
|
||||
|
||||
private final Chat data;
|
||||
|
||||
public TGToStringFromChat(Chat chat) {
|
||||
@ -20,4 +25,36 @@ public class TGToStringFromChat {
|
||||
(String.format("%s {%s}[%d]", data.title(), data.username(), data.id()));
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getSafeName () {
|
||||
if (data.type() == Chat.Type.Private)
|
||||
return data.firstName() + (data.lastName()==null ? "" : " "+data.lastName());
|
||||
else return data.title();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getSafeLinkHTML () {
|
||||
if (data.username() == null) {
|
||||
if (data.type() == Chat.Type.Private)
|
||||
// language=html
|
||||
return String.format("<a href='tg://user?id=%d'>@[u:%d]</a>", data.id(), data.id());
|
||||
// language=html
|
||||
else return String.format("<a href='https://t.me/c/%d'>@[c/%d]</a>", id_tdLib(), id_tdLib());
|
||||
} else return "@"+data.username();
|
||||
}
|
||||
|
||||
public long id_tdLib () {
|
||||
return data.id() < 0 ? Math.abs(data.id() - MASK_BOTAPI_ID) : data.id();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getTypeTag () {
|
||||
return switch (data.type()) {
|
||||
case Private -> "🔒";
|
||||
case group -> "💭";
|
||||
case supergroup -> "💬";
|
||||
case channel -> "📢";
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,22 @@
|
||||
package cc.sukazyo.cono.morny.bot.api
|
||||
|
||||
import com.pengrad.telegrambot.model.Update
|
||||
|
||||
trait EventListener {
|
||||
|
||||
def onMessage (using Update): Boolean = false
|
||||
def onEditedMessage (using Update): Boolean = false
|
||||
def onChannelPost (using Update): Boolean = false
|
||||
def onEditedChannelPost (using Update): Boolean = false
|
||||
def onInlineQuery (using Update): Boolean = false
|
||||
def onChosenInlineResult (using Update): Boolean = false
|
||||
def onCallbackQuery (using Update): Boolean = false
|
||||
def onShippingQuery (using Update): Boolean = false
|
||||
def onPreCheckoutQuery (using Update): Boolean = false
|
||||
def onPoll (using Update): Boolean = false
|
||||
def onPollAnswer (using Update): Boolean = false
|
||||
def onMyChatMemberUpdated (using Update): Boolean = false
|
||||
def onChatMemberUpdated (using Update): Boolean = false
|
||||
def onChatJoinRequest (using Update): Boolean = false
|
||||
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
package cc.sukazyo.cono.morny.bot.api
|
||||
|
||||
import cc.sukazyo.cono.morny.Log
|
||||
import cc.sukazyo.cono.morny.util.tgapi.event.EventRuntimeException
|
||||
import cc.sukazyo.cono.morny.Log.{exceptionLog, logger}
|
||||
import cc.sukazyo.cono.morny.daemon.MornyReport
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.pengrad.telegrambot.model.Update
|
||||
|
||||
import scala.collection.mutable
|
||||
import scala.language.postfixOps
|
||||
|
||||
object EventListenerManager {
|
||||
|
||||
private val listeners = mutable.Queue.empty[EventListener]
|
||||
|
||||
def register (listeners: EventListener*): Unit =
|
||||
this.listeners ++= listeners
|
||||
|
||||
private class EventRunner (using event: Update) extends Thread {
|
||||
this setName s"evt-${event.updateId()}-nn"
|
||||
private def updateThreadName (t: String): Unit =
|
||||
this setName s"evt-${event.updateId()}-$t"
|
||||
|
||||
override def run (): Unit = {
|
||||
for (i <- listeners) {
|
||||
object status:
|
||||
var _status = 0
|
||||
def isOk: Boolean = _status > 0
|
||||
def check (u: Boolean): Unit = if u then _status = _status + 1
|
||||
try {
|
||||
updateThreadName("message")
|
||||
if event.message ne null then status check i.onMessage
|
||||
updateThreadName("edited-message")
|
||||
if event.editedMessage ne null then status check i.onEditedMessage
|
||||
updateThreadName("channel-post")
|
||||
if event.channelPost ne null then status check i.onChannelPost
|
||||
updateThreadName("edited-channel-post")
|
||||
if event.editedChannelPost ne null then status check i.onEditedChannelPost
|
||||
updateThreadName("inline-query")
|
||||
if event.inlineQuery ne null then status check i.onInlineQuery
|
||||
updateThreadName("chosen-inline-result")
|
||||
if event.chosenInlineResult ne null then status check i.onChosenInlineResult
|
||||
updateThreadName("callback-query")
|
||||
if event.callbackQuery ne null then status check i.onCallbackQuery
|
||||
updateThreadName("shipping-query")
|
||||
if event.shippingQuery ne null then status check i.onShippingQuery
|
||||
updateThreadName("pre-checkout-query")
|
||||
if event.preCheckoutQuery ne null then status check i.onPreCheckoutQuery
|
||||
updateThreadName("poll")
|
||||
if event.poll ne null then status check i.onPoll
|
||||
updateThreadName("poll-answer")
|
||||
if event.pollAnswer ne null then status check i.onPollAnswer
|
||||
updateThreadName("my-chat-member")
|
||||
if event.myChatMember ne null then status check i.onMyChatMemberUpdated
|
||||
updateThreadName("chat-member")
|
||||
if event.chatMember ne null then status check i.onChatMemberUpdated
|
||||
updateThreadName("chat-join-request")
|
||||
if event.chatJoinRequest ne null then status check i.onChatJoinRequest
|
||||
} catch case e => {
|
||||
val errorMessage = StringBuilder()
|
||||
errorMessage ++= "Event throws unexpected exception:\n"
|
||||
errorMessage ++= (exceptionLog(e) indent 4)
|
||||
e match
|
||||
case actionFailed: EventRuntimeException.ActionFailed =>
|
||||
errorMessage ++= "\ntg-api action: response track: "
|
||||
errorMessage ++= (GsonBuilder().setPrettyPrinting().create().toJson(
|
||||
actionFailed.getResponse
|
||||
) indent 4) ++= "\n"
|
||||
case _ =>
|
||||
logger error errorMessage.toString
|
||||
MornyReport.exception(e, "on event running")
|
||||
}
|
||||
if (status isOk) return
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
def publishUpdate (using Update): Unit = {
|
||||
EventRunner().start()
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package cc.sukazyo.cono.morny.bot.api
|
||||
|
||||
import com.pengrad.telegrambot.UpdatesListener
|
||||
import com.pengrad.telegrambot.model.Update
|
||||
|
||||
import java.util
|
||||
import scala.jdk.CollectionConverters.*
|
||||
|
||||
object TelegramUpdatesListener extends UpdatesListener {
|
||||
|
||||
override def process (updates: util.List[Update]): Int = {
|
||||
for (update <- updates.asScala)
|
||||
EventListenerManager.publishUpdate(using update)
|
||||
UpdatesListener.CONFIRMED_UPDATES_ALL
|
||||
}
|
||||
|
||||
}
|
@ -11,10 +11,10 @@ import scala.language.postfixOps
|
||||
|
||||
object DirectMsgClear extends ISimpleCommand {
|
||||
|
||||
override def getName: String = "r"
|
||||
override def getAliases: Array[String] = null
|
||||
override val name: String = "r"
|
||||
override val aliases: Array[ICommandAlias] | Null = null
|
||||
|
||||
override def execute (command: InputCommand, event: Update): Unit = {
|
||||
override def execute (using command: InputCommand, event: Update): Unit = {
|
||||
|
||||
logger debug "executing command /r"
|
||||
if (event.message.replyToMessage == null) return;
|
||||
|
@ -18,12 +18,12 @@ import scala.language.postfixOps
|
||||
|
||||
object Encryptor extends ITelegramCommand {
|
||||
|
||||
override def getName: String = "encrypt"
|
||||
override def getAliases: Array[String] = null
|
||||
override def getParamRule: String = "[algorithm|(l)] [(uppercase)]"
|
||||
override def getDescription: String = "通过指定算法加密回复的内容 (目前只支持文本)"
|
||||
override val name: String = "encrypt"
|
||||
override val aliases: Array[ICommandAlias] | Null = null
|
||||
override val paramRule: String = "[algorithm|(l)] [(uppercase)]"
|
||||
override val description: String = "通过指定算法加密回复的内容 (目前只支持文本)"
|
||||
|
||||
override def execute (command: InputCommand, event: Update): Unit = {
|
||||
override def execute (using command: InputCommand, event: Update): Unit = {
|
||||
|
||||
val args = command.getArgs
|
||||
|
||||
|
@ -11,12 +11,12 @@ import scala.language.postfixOps
|
||||
|
||||
object EventHack extends ITelegramCommand {
|
||||
|
||||
override def getName: String = "event_hack"
|
||||
override def getAliases: Array[String] = null
|
||||
override def getParamRule: String = "[(user|group|any)]"
|
||||
override def getDescription: String = "输出 bot 下一个获取到的事件序列化数据"
|
||||
override val name: String = "event_hack"
|
||||
override val aliases: Array[ICommandAlias] | Null = null
|
||||
override val paramRule: String = "[(user|group|any)]"
|
||||
override val description: String = "输出 bot 下一个获取到的事件序列化数据"
|
||||
|
||||
override def execute (command: InputCommand, event: Update): Unit = {
|
||||
override def execute (using command: InputCommand, event: Update): Unit = {
|
||||
|
||||
val x_mode = if (command.hasArgs) command.getArgs()(0) else ""
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
package cc.sukazyo.cono.morny.bot.command
|
||||
|
||||
import cc.sukazyo.cono.morny.MornyCoeur
|
||||
import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramUserInformation
|
||||
import cc.sukazyo.cono.morny.util.tgapi.{InputCommand, Standardize}
|
||||
import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramUserInformation
|
||||
import com.pengrad.telegrambot.model.Update
|
||||
import com.pengrad.telegrambot.model.request.ParseMode
|
||||
import com.pengrad.telegrambot.request.{GetChatMember, SendMessage}
|
||||
@ -10,12 +11,12 @@ import scala.language.postfixOps
|
||||
|
||||
object GetUsernameAndId extends ITelegramCommand {
|
||||
|
||||
override def getName: String = "user"
|
||||
override def getAliases: Array[String] = Array()
|
||||
override def getParamRule: String = "[userid]"
|
||||
override def getDescription: String = "获取指定或回复的用户相关信息"
|
||||
override val name: String = "user"
|
||||
override val aliases: Array[ICommandAlias] | Null = null
|
||||
override val paramRule: String = "[userid]"
|
||||
override val description: String = "获取指定或回复的用户相关信息"
|
||||
|
||||
override def execute (command: InputCommand, event: Update): Unit = {
|
||||
override def execute (using command: InputCommand, event: Update): Unit = {
|
||||
|
||||
val args = command.getArgs
|
||||
|
||||
@ -49,7 +50,7 @@ object GetUsernameAndId extends ITelegramCommand {
|
||||
|
||||
val user = response.chatMember.user
|
||||
|
||||
if (user.id eq Standardize.CHANNEL_SPEAKER_MAGIC_ID)
|
||||
if (user.id == Standardize.CHANNEL_SPEAKER_MAGIC_ID)
|
||||
MornyCoeur.extra exec SendMessage(
|
||||
event.message.chat.id,
|
||||
"<code>$__channel_identify</code>"
|
||||
|
@ -0,0 +1,18 @@
|
||||
package cc.sukazyo.cono.morny.bot.command
|
||||
|
||||
trait ICommandAlias {
|
||||
|
||||
val name: String
|
||||
val listed: Boolean
|
||||
|
||||
}
|
||||
|
||||
object ICommandAlias {
|
||||
|
||||
case class ListedAlias (name: String) extends ICommandAlias:
|
||||
override val listed = true
|
||||
|
||||
case class HiddenAlias (name: String) extends ICommandAlias:
|
||||
override val listed = false
|
||||
|
||||
}
|
@ -16,19 +16,19 @@ object IP186Query {
|
||||
case WHOIS extends Subs("whois")
|
||||
|
||||
object IP extends ITelegramCommand:
|
||||
override def getName: String = "ip"
|
||||
override def getAliases: Array[String] = null
|
||||
override def getParamRule: String = "[ip]"
|
||||
override def getDescription: String = "通过 https://ip.186526.xyz 查询 ip 资料"
|
||||
override def execute (command: InputCommand, event: Update): Unit = query(event, command)
|
||||
override val name: String = "ip"
|
||||
override val aliases: Array[ICommandAlias]|Null = null
|
||||
override val paramRule: String = "[ip]"
|
||||
override val description: String = "通过 https://ip.186526.xyz 查询 ip 资料"
|
||||
override def execute (using command: InputCommand, event: Update): Unit = query
|
||||
object Whois extends ITelegramCommand:
|
||||
override def getName: String = "whois"
|
||||
override def getAliases: Array[String] = null
|
||||
override def getParamRule: String = "[domain]"
|
||||
override def getDescription: String = "通过 https://ip.186526.xyz 查询域名资料"
|
||||
override def execute (command: InputCommand, event: Update): Unit = query(event, command)
|
||||
override val name: String = "whois"
|
||||
override val aliases: Array[ICommandAlias]|Null = null
|
||||
override val paramRule: String = "[domain]"
|
||||
override val description: String = "通过 https://ip.186526.xyz 查询域名资料"
|
||||
override def execute (using command: InputCommand, event: Update): Unit = query
|
||||
|
||||
private def query (event: Update, command: InputCommand): Unit = {
|
||||
private def query (using event: Update, command: InputCommand): Unit = {
|
||||
|
||||
val target: String|Null =
|
||||
if (command.getArgs isEmpty)
|
||||
|
@ -0,0 +1,13 @@
|
||||
package cc.sukazyo.cono.morny.bot.command
|
||||
|
||||
import cc.sukazyo.cono.morny.util.tgapi.InputCommand
|
||||
import com.pengrad.telegrambot.model.Update
|
||||
|
||||
trait ISimpleCommand {
|
||||
|
||||
val name: String
|
||||
val aliases: Array[ICommandAlias]|Null
|
||||
|
||||
def execute (using command: InputCommand, event: Update): Unit
|
||||
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package cc.sukazyo.cono.morny.bot.command
|
||||
|
||||
trait ITelegramCommand extends ISimpleCommand {
|
||||
|
||||
val paramRule: String
|
||||
val description: String
|
||||
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
package cc.sukazyo.cono.morny.bot.command
|
||||
|
||||
import cc.sukazyo.cono.morny.util.tgapi.InputCommand
|
||||
import cc.sukazyo.cono.morny.MornyCoeur
|
||||
import cc.sukazyo.cono.morny.data.TelegramStickers
|
||||
import com.pengrad.telegrambot.model.{BotCommand, DeleteMyCommands, Update}
|
||||
import com.pengrad.telegrambot.request.{SendSticker, SetMyCommands}
|
||||
|
||||
import scala.collection.{mutable, SeqMap}
|
||||
import scala.collection.mutable.ArrayBuffer
|
||||
import scala.language.postfixOps
|
||||
import cc.sukazyo.cono.morny.Log.logger
|
||||
|
||||
object MornyCommands {
|
||||
|
||||
private type CommandMap = SeqMap[String, ISimpleCommand]
|
||||
private def CommandMap (commands: ISimpleCommand*): CommandMap =
|
||||
val stash: mutable.SeqMap[String, ISimpleCommand] = mutable.SeqMap()
|
||||
for (i <- commands) stash += ((i.name, i))
|
||||
stash
|
||||
|
||||
private val commands: CommandMap = CommandMap(
|
||||
|
||||
MornyHellos.On,
|
||||
MornyHellos.On,
|
||||
MornyHellos.Hello,
|
||||
MornyInfoOnStart,
|
||||
GetUsernameAndId,
|
||||
EventHack,
|
||||
Nbnhhsh,
|
||||
IP186Query.IP,
|
||||
IP186Query.Whois,
|
||||
Encryptor,
|
||||
MornyManagers.SaveData,
|
||||
MornyInformation,
|
||||
MornyInformationOlds.Version,
|
||||
MornyInformationOlds.Runtime,
|
||||
MornyOldJrrp,
|
||||
MornyManagers.Exit,
|
||||
|
||||
Testing,
|
||||
DirectMsgClear,
|
||||
|
||||
私わね,
|
||||
喵呜.Progynova
|
||||
|
||||
)
|
||||
|
||||
@SuppressWarnings(Array("NonAsciiCharacters"))
|
||||
val commands_uni: CommandMap = CommandMap(
|
||||
喵呜.抱抱,
|
||||
喵呜.揉揉,
|
||||
喵呜.贴贴,
|
||||
喵呜.蹭蹭
|
||||
)
|
||||
|
||||
def execute (using command: InputCommand, event: Update): Boolean = {
|
||||
if (commands contains command.getCommand)
|
||||
commands(command.getCommand) execute;
|
||||
true
|
||||
else nonCommandExecutable
|
||||
}
|
||||
|
||||
private def nonCommandExecutable (using command: InputCommand, event: Update): Boolean = {
|
||||
if command.getTarget eq null then false
|
||||
else
|
||||
MornyCoeur.extra exec SendSticker(
|
||||
event.message.chat.id,
|
||||
TelegramStickers ID_404
|
||||
).replyToMessageId(event.message.messageId)
|
||||
true
|
||||
}
|
||||
|
||||
def automaticTGListUpdate (): Unit = {
|
||||
val listing = commands_toTelegramList
|
||||
automaticTGListRemove()
|
||||
MornyCoeur.extra exec SetMyCommands(listing:_*)
|
||||
logger info
|
||||
s"""automatic updated telegram command list :
|
||||
|${commandsTelegramList_toString(listing)}""".stripMargin
|
||||
}
|
||||
|
||||
def automaticTGListRemove (): Unit = {
|
||||
MornyCoeur.extra exec DeleteMyCommands()
|
||||
logger info "cleaned up command list"
|
||||
}
|
||||
|
||||
private def commandsTelegramList_toString (list: Array[BotCommand]): String =
|
||||
val builder = StringBuilder()
|
||||
for (single <- list)
|
||||
builder ++= s"${single.command} - ${single.description}\n"
|
||||
(builder dropRight 1) toString
|
||||
|
||||
private def commands_toTelegramList: Array[BotCommand] =
|
||||
val list = ArrayBuffer.empty[BotCommand]
|
||||
for ((name, command) <- commands) command match
|
||||
case telegramCommand: ITelegramCommand if name == command.name =>
|
||||
list ++= formatTelegramCommandListLine(telegramCommand)
|
||||
case _ =>
|
||||
list toArray
|
||||
|
||||
private def formatTelegramCommandListLine (command: ITelegramCommand): Array[BotCommand] =
|
||||
def buildOne (name: String, paramRule: String, intro: String): BotCommand =
|
||||
BotCommand(name, if paramRule isBlank then intro else s"$paramRule - $intro")
|
||||
val list = mutable.ArrayBuffer[BotCommand](
|
||||
buildOne(command.name, command.paramRule, command.description))
|
||||
if (command.aliases ne null) for (alias <- command.aliases)
|
||||
if (alias.listed) list += buildOne(alias.name, "", "↑")
|
||||
list toArray
|
||||
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package cc.sukazyo.cono.morny.bot.command
|
||||
import cc.sukazyo.cono.morny.util.tgapi.InputCommand
|
||||
import cc.sukazyo.cono.morny.MornyCoeur
|
||||
import cc.sukazyo.cono.morny.bot.command.ICommandAlias.ListedAlias
|
||||
import cc.sukazyo.cono.morny.data.TelegramStickers
|
||||
import com.pengrad.telegrambot.model.Update
|
||||
import com.pengrad.telegrambot.request.SendSticker
|
||||
|
||||
import scala.language.postfixOps
|
||||
|
||||
object MornyHellos {
|
||||
|
||||
object On extends ITelegramCommand {
|
||||
|
||||
override val name: String = "on"
|
||||
override val aliases: Array[ICommandAlias] | Null = null
|
||||
override val paramRule: String = ""
|
||||
override val description: String = "检查是否在线"
|
||||
|
||||
override def execute (using command: InputCommand, event: Update): Unit =
|
||||
MornyCoeur.extra exec SendSticker(
|
||||
event.message.chat.id,
|
||||
TelegramStickers ID_ONLINE_STATUS_RETURN
|
||||
).replyToMessageId(event.message.messageId)
|
||||
|
||||
}
|
||||
|
||||
object Hello extends ITelegramCommand {
|
||||
|
||||
override val name: String = "hello"
|
||||
override val aliases: Array[ICommandAlias] | Null = Array(ListedAlias("hi"))
|
||||
override val paramRule: String = ""
|
||||
override val description: String = "打招呼"
|
||||
|
||||
override def execute (using command: InputCommand, event: Update): Unit =
|
||||
MornyCoeur.extra exec SendSticker(
|
||||
event.message.chat.id,
|
||||
TelegramStickers ID_HELLO
|
||||
).replyToMessageId(event.message.messageId)
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -8,12 +8,12 @@ import com.pengrad.telegrambot.request.SendPhoto
|
||||
|
||||
import scala.language.postfixOps
|
||||
|
||||
object MornyInfoOnHello extends ISimpleCommand {
|
||||
object MornyInfoOnStart extends ISimpleCommand {
|
||||
|
||||
override def getName: String = "start"
|
||||
override def getAliases: Array[String] = Array()
|
||||
override val name: String = "start"
|
||||
override val aliases: Array[ICommandAlias] | Null = null
|
||||
|
||||
override def execute (command: InputCommand, event: Update): Unit = {
|
||||
override def execute (using command: InputCommand, event: Update): Unit = {
|
||||
|
||||
MornyCoeur.extra exec new SendPhoto(
|
||||
event.message.chat.id,
|
@ -23,12 +23,12 @@ object MornyInformation extends ITelegramCommand {
|
||||
val VERSION_2 = "v"
|
||||
}
|
||||
|
||||
override def getName: String = "info"
|
||||
override def getAliases: Array[String] = Array()
|
||||
override def getParamRule: String = "[(version|runtime|stickers[.IDs])]"
|
||||
override def getDescription: String = "输出当前 Morny 的各种信息"
|
||||
override val name: String = "info"
|
||||
override val aliases: Array[ICommandAlias]|Null = null
|
||||
override val paramRule: String = "[(version|runtime|stickers[.IDs])]"
|
||||
override val description: String = "输出当前 Morny 的各种信息"
|
||||
|
||||
override def execute (command: InputCommand, event: Update): Unit = {
|
||||
override def execute (using command: InputCommand, event: Update): Unit = {
|
||||
|
||||
if (!command.hasArgs) {
|
||||
echoInfo(event.message.chat.id, event.message.messageId)
|
||||
@ -38,10 +38,10 @@ object MornyInformation extends ITelegramCommand {
|
||||
val action: String = command.getArgs()(0)
|
||||
|
||||
action match {
|
||||
case Subs.STICKERS => echoStickers(command, event)
|
||||
case Subs.RUNTIME => echoRuntime(event)
|
||||
case Subs.VERSION | Subs.VERSION_2 => echoVersion(event)
|
||||
case _ => echo404(event)
|
||||
case Subs.STICKERS => echoStickers
|
||||
case Subs.RUNTIME => echoRuntime
|
||||
case Subs.VERSION | Subs.VERSION_2 => echoVersion
|
||||
case _ => echo404
|
||||
}
|
||||
|
||||
}
|
||||
@ -92,11 +92,11 @@ object MornyInformation extends ITelegramCommand {
|
||||
).parseMode(ParseMode HTML).replyToMessageId(replyTo)
|
||||
}
|
||||
|
||||
private def echoStickers (command: InputCommand, event: Update): Unit = {
|
||||
private def echoStickers (using command: InputCommand, event: Update): Unit = {
|
||||
val chat = event.message.chat.id
|
||||
val replyTo = event.message.messageId
|
||||
var sid: String|Null = null
|
||||
if (command.getArgs()(0) eq Subs.STICKERS) {
|
||||
if (command.getArgs()(0) == Subs.STICKERS) {
|
||||
if (command.getArgs.length == 1) sid = ""
|
||||
else if (command.getArgs.length == 2) sid = command.getArgs()(1)
|
||||
} else if (command.getArgs.length == 1) {
|
||||
@ -104,7 +104,7 @@ object MornyInformation extends ITelegramCommand {
|
||||
sid = command.getArgs()(0) substring Subs.STICKERS.length+1
|
||||
}
|
||||
}
|
||||
if (sid == null) echo404(event)
|
||||
if (sid == null) echo404
|
||||
else echoStickers(sid, chat, replyTo)
|
||||
}
|
||||
|
||||
@ -113,11 +113,12 @@ object MornyInformation extends ITelegramCommand {
|
||||
else TelegramStickers echoStickerByID(sid, MornyCoeur.extra, send_chat, send_replyTo)
|
||||
}
|
||||
|
||||
private[command] def echoVersion (event: Update): Unit = {
|
||||
private[command] def echoVersion (using event: Update): Unit = {
|
||||
val versionDeltaHTML = if (MornySystem.isUseDelta) s"-δ<code>${h(MornySystem.VERSION_DELTA)}</code>" else ""
|
||||
val versionGitHTML = if (MornySystem.isGitBuild) s"git $getVersionGitTagHTML" else ""
|
||||
MornyCoeur.extra exec new SendMessage(
|
||||
event.message.chat.id,
|
||||
// language=html
|
||||
s"""version:
|
||||
|- Morny <code>${h(MornySystem.CODENAME toUpperCase)}</code>
|
||||
|- <code>${h(MornySystem.VERSION_BASE)}</code>$versionDeltaHTML${if (MornySystem.isGitBuild) "\n- " + versionGitHTML else ""}
|
||||
@ -130,11 +131,11 @@ object MornyInformation extends ITelegramCommand {
|
||||
).replyToMessageId(event.message.messageId).parseMode(ParseMode HTML)
|
||||
}
|
||||
|
||||
private[command] def echoRuntime (event: Update): Unit = {
|
||||
private[command] def echoRuntime (using event: Update): Unit = {
|
||||
def sysprop (p: String): String = System.getProperty(p)
|
||||
MornyCoeur.extra exec new SendMessage(
|
||||
event.message.chat.id,
|
||||
/* html */
|
||||
/* language=html */
|
||||
s"""system:
|
||||
|- Morny <code>${h(if (getRuntimeHostname == null) "<unknown-host>" else getRuntimeHostname)}</code>
|
||||
|- <code>${h(sysprop("os.name"))}</code> <code>${h(sysprop("os.arch"))}</code> <code>${h(sysprop("os.version"))}</code>
|
||||
@ -158,7 +159,7 @@ object MornyInformation extends ITelegramCommand {
|
||||
).parseMode(ParseMode HTML).replyToMessageId(event.message.messageId)
|
||||
}
|
||||
|
||||
private def echo404 (event: Update): Unit =
|
||||
private def echo404 (using event: Update): Unit =
|
||||
MornyCoeur.extra exec new SendSticker(
|
||||
event.message.chat.id,
|
||||
TelegramStickers ID_404
|
||||
|
@ -0,0 +1,17 @@
|
||||
package cc.sukazyo.cono.morny.bot.command
|
||||
import cc.sukazyo.cono.morny.util.tgapi.InputCommand
|
||||
import com.pengrad.telegrambot.model.Update
|
||||
|
||||
object MornyInformationOlds {
|
||||
|
||||
object Version extends ISimpleCommand:
|
||||
override val name: String = "version"
|
||||
override val aliases: Array[ICommandAlias] | Null = null
|
||||
override def execute (using command: InputCommand, event: Update): Unit = MornyInformation.echoVersion
|
||||
|
||||
object Runtime extends ISimpleCommand:
|
||||
override val name: String = "runtime"
|
||||
override val aliases: Array[ICommandAlias] | Null = null
|
||||
override def execute (using command: InputCommand, event: Update): Unit = MornyInformation.echoRuntime
|
||||
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
package cc.sukazyo.cono.morny.bot.command
|
||||
import cc.sukazyo.cono.morny.bot.command.ICommandAlias.HiddenAlias
|
||||
import cc.sukazyo.cono.morny.util.tgapi.InputCommand
|
||||
import cc.sukazyo.cono.morny.MornyCoeur
|
||||
import cc.sukazyo.cono.morny.data.TelegramStickers
|
||||
import cc.sukazyo.cono.morny.util.tgapi.formatting.TGToString
|
||||
import com.pengrad.telegrambot.model.Update
|
||||
import com.pengrad.telegrambot.request.SendSticker
|
||||
|
||||
import scala.language.postfixOps
|
||||
import cc.sukazyo.cono.morny.Log.logger
|
||||
import cc.sukazyo.cono.morny.daemon.MornyReport
|
||||
|
||||
object MornyManagers {
|
||||
|
||||
object Exit extends ITelegramCommand {
|
||||
|
||||
override val name: String = "exit"
|
||||
override val aliases: Array[ICommandAlias] | Null = Array(HiddenAlias("stop"), HiddenAlias("quit"))
|
||||
override val paramRule: String = "exit"
|
||||
override val description: String = "关闭 Bot (仅可信成员)"
|
||||
|
||||
override def execute (using command: InputCommand, event: Update): Unit = {
|
||||
|
||||
val user = event.message.from
|
||||
|
||||
if (MornyCoeur.trustedInstance isTrusted user.id) {
|
||||
|
||||
MornyCoeur.extra exec SendSticker(
|
||||
event.message.chat.id,
|
||||
TelegramStickers ID_EXIT
|
||||
).replyToMessageId(event.message.messageId)
|
||||
logger info s"Morny exited by user ${(TGToString as user) toStringLogTag}"
|
||||
MornyCoeur.exit(0, user)
|
||||
|
||||
} else {
|
||||
|
||||
MornyCoeur.extra exec SendSticker(
|
||||
event.message.chat.id,
|
||||
TelegramStickers ID_403
|
||||
).replyToMessageId(event.message.messageId)
|
||||
logger info s"403 exit caught from user ${(TGToString as user) toStringLogTag}"
|
||||
MornyReport.unauthenticatedAction("/exit", user)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
object SaveData extends ITelegramCommand {
|
||||
|
||||
override val name: String = "save"
|
||||
override val aliases: Array[ICommandAlias] | Null = null
|
||||
override val paramRule: String = ""
|
||||
override val description: String = "保存缓存数据到文件(仅可信成员)"
|
||||
|
||||
override def execute (using command: InputCommand, event: Update): Unit = {
|
||||
|
||||
val user = event.message.from
|
||||
|
||||
if (MornyCoeur.trustedInstance isTrusted user.id) {
|
||||
|
||||
logger info s"call save from command by ${(TGToString as user) toStringLogTag}"
|
||||
MornyCoeur.callSaveData()
|
||||
MornyCoeur.extra exec SendSticker(
|
||||
event.message.chat.id,
|
||||
TelegramStickers ID_SAVED
|
||||
).replyToMessageId(event.message.messageId)
|
||||
|
||||
} else {
|
||||
|
||||
MornyCoeur.extra exec SendSticker(
|
||||
event.message.chat.id,
|
||||
TelegramStickers ID_403
|
||||
).replyToMessageId(event.message.messageId)
|
||||
logger info s"403 save caught from user ${(TGToString as user) toStringLogTag}"
|
||||
MornyReport.unauthenticatedAction("/save", user)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package cc.sukazyo.cono.morny.bot.command
|
||||
import cc.sukazyo.cono.morny.util.tgapi.InputCommand
|
||||
import com.pengrad.telegrambot.model.Update
|
||||
import cc.sukazyo.cono.morny.data.MornyJrrp
|
||||
import cc.sukazyo.cono.morny.MornyCoeur
|
||||
import cc.sukazyo.cono.morny.util.tgapi.formatting.TGToString
|
||||
import com.pengrad.telegrambot.model.request.ParseMode
|
||||
import com.pengrad.telegrambot.request.SendMessage
|
||||
|
||||
import scala.language.postfixOps
|
||||
object MornyOldJrrp extends ITelegramCommand {
|
||||
|
||||
override val name: String = "jrrp"
|
||||
override val aliases: Array[ICommandAlias] | Null = null
|
||||
override val paramRule: String = ""
|
||||
override val description: String = "获取 (假的) jrrp"
|
||||
|
||||
override def execute (using command: InputCommand, event: Update): Unit = {
|
||||
|
||||
val user = event.message.from
|
||||
val jrrp = MornyJrrp.jrrp_of_telegramUser(user, System.currentTimeMillis)
|
||||
val ending = jrrp match
|
||||
case s if s > 70 => "!"
|
||||
case a if a > 30 => ";"
|
||||
case _ => "..."
|
||||
|
||||
import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h
|
||||
MornyCoeur.extra exec SendMessage(
|
||||
event.message.chat.id,
|
||||
// language=html
|
||||
f"${(TGToString as user) fullnameRefHtml} 在(utc的)今天的运气指数是———— <code>$jrrp%.2f%%</code>${h(ending)}"
|
||||
).replyToMessageId(event.message.messageId).parseMode(ParseMode HTML)
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -13,14 +13,16 @@ import scala.language.postfixOps
|
||||
|
||||
object Nbnhhsh extends ITelegramCommand {
|
||||
|
||||
private val NBNHHSH_RESULT_HEAD_HTML = "<a href=\"https://lab.magiconch.com/nbnhhsh/\">## Result of nbnhhsh query :</a>"
|
||||
private val NBNHHSH_RESULT_HEAD_HTML =
|
||||
// language=html
|
||||
"<a href=\"https://lab.magiconch.com/nbnhhsh/\">## Result of nbnhhsh query :</a>"
|
||||
|
||||
override def getName: String = "nbnhhsh"
|
||||
override def getAliases: Array[String]|Null = null
|
||||
override def getParamRule: String = "[text]"
|
||||
override def getDescription: String = "检索文本内 nbnhhsh 词条"
|
||||
override val name: String = "nbnhhsh"
|
||||
override val aliases: Array[ICommandAlias]|Null = null
|
||||
override val paramRule: String = "[text]"
|
||||
override val description: String = "检索文本内 nbnhhsh 词条"
|
||||
|
||||
override def execute (command: InputCommand, event: Update): Unit = {
|
||||
override def execute (using command: InputCommand, event: Update): Unit = {
|
||||
|
||||
val queryTarget: String|Null =
|
||||
import cc.sukazyo.cono.morny.util.CommonConvert.stringsConnecting
|
||||
@ -47,17 +49,17 @@ object Nbnhhsh extends ITelegramCommand {
|
||||
logger debug s"**xx len=${queryResp.words.length}"
|
||||
for (_word <- queryResp.words) {
|
||||
logger debug "**exec"
|
||||
if ((_word.trans ne null) && (_word.trans isEmpty)) _word.trans = null
|
||||
if ((_word.inputting ne null) && (_word.inputting isEmpty)) _word.inputting = null
|
||||
if ((_word.trans ne null) || (_word.inputting ne null))
|
||||
val _use_trans = (_word.trans ne null) && (_word.trans nonEmpty)
|
||||
val _use_inputting = (_word.inputting ne null) && (_word.inputting nonEmpty)
|
||||
if (_use_trans || _use_inputting)
|
||||
message ++= s"\n\n<b>[[ ${h(_word.name)} ]]</b>"
|
||||
logger debug s"**used [${_word.name}]"
|
||||
if (_word.trans != null) for (_trans <- _word.trans)
|
||||
if (_use_trans) for (_trans <- _word.trans)
|
||||
message ++= s"\n* <i>${h(_trans)}</i>"
|
||||
logger debug s"**used [${_word.name}] used `${_trans}``"
|
||||
if (_word.inputting != null)
|
||||
if (_use_inputting)
|
||||
logger debug s"**used [${_word.name}] inputting"
|
||||
if (_word.trans != null)
|
||||
if (_use_trans)
|
||||
message += '\n'
|
||||
message ++= " maybe:"
|
||||
for (_inputting <- _word.inputting)
|
||||
|
@ -12,17 +12,15 @@ import scala.language.postfixOps
|
||||
|
||||
object Testing extends ISimpleCommand {
|
||||
|
||||
override def getName: String = "test"
|
||||
override def getAliases: Array[String] = null
|
||||
override val name: String = "test"
|
||||
override val aliases: Array[ICommandAlias] | Null = null
|
||||
|
||||
override def execute (command: InputCommand, event: Update): Unit = {
|
||||
|
||||
val a = StringBuilder("value")
|
||||
a ++= "Changed"
|
||||
override def execute (using command: InputCommand, event: Update): Unit = {
|
||||
|
||||
MornyCoeur.extra exec new SendMessage(
|
||||
event.message.chat.id,
|
||||
"<b>Just</b> a TEST command. num is:" + (a toString)
|
||||
// language=html
|
||||
"<b>Just</b> a TEST command."
|
||||
).replyToMessageId(event.message.messageId).parseMode(ParseMode HTML)
|
||||
|
||||
}
|
||||
|
@ -15,39 +15,39 @@ import scala.language.postfixOps
|
||||
object 喵呜 {
|
||||
|
||||
object 抱抱 extends ISimpleCommand {
|
||||
override def getName: String = "抱抱"
|
||||
override def getAliases: Array[String] = Array()
|
||||
override def execute (command: InputCommand, event: Update): Unit =
|
||||
replyingSet(event, "贴贴", "贴贴")
|
||||
override val name: String = "抱抱"
|
||||
override val aliases: Array[ICommandAlias]|Null = null
|
||||
override def execute (using command: InputCommand, event: Update): Unit =
|
||||
replyingSet("贴贴", "贴贴")
|
||||
}
|
||||
|
||||
object 揉揉 extends ISimpleCommand {
|
||||
override def getName: String = "揉揉"
|
||||
override def getAliases: Array[String] = Array()
|
||||
override def execute (command: InputCommand, event: Update): Unit =
|
||||
replyingSet(event, "蹭蹭", "摸摸")
|
||||
override val name: String = "揉揉"
|
||||
override val aliases: Array[ICommandAlias]|Null = null
|
||||
override def execute (using command: InputCommand, event: Update): Unit =
|
||||
replyingSet("蹭蹭", "摸摸")
|
||||
}
|
||||
|
||||
object 蹭蹭 extends ISimpleCommand {
|
||||
override def getName: String = "蹭蹭"
|
||||
override def getAliases: Array[String] = Array()
|
||||
override def execute (command: InputCommand, event: Update): Unit =
|
||||
replyingSet(event, "揉揉", "蹭蹭")
|
||||
override val name: String = "蹭蹭"
|
||||
override val aliases: Array[ICommandAlias]|Null = null
|
||||
override def execute (using command: InputCommand, event: Update): Unit =
|
||||
replyingSet("揉揉", "蹭蹭")
|
||||
}
|
||||
|
||||
object 贴贴 extends ISimpleCommand {
|
||||
override def getName: String = "贴贴"
|
||||
override def getAliases: Array[String] = Array()
|
||||
override def execute (command: InputCommand, event: Update): Unit =
|
||||
replyingSet(event, "贴贴", "贴贴")
|
||||
override val name: String = "贴贴"
|
||||
override val aliases: Array[ICommandAlias]|Null = null
|
||||
override def execute (using command: InputCommand, event: Update): Unit =
|
||||
replyingSet("贴贴", "贴贴")
|
||||
}
|
||||
|
||||
object Progynova extends ITelegramCommand {
|
||||
override def getName: String = "install"
|
||||
override def getAliases: Array[String] = Array()
|
||||
override def getParamRule: String = ""
|
||||
override def getDescription: String = "抽取一个神秘盒子"
|
||||
override def execute (command: InputCommand, event: Update): Unit = {
|
||||
override val name: String = "install"
|
||||
override val aliases: Array[ICommandAlias]|Null = null
|
||||
override val paramRule: String = ""
|
||||
override val description: String = "抽取一个神秘盒子"
|
||||
override def execute (using command: InputCommand, event: Update): Unit = {
|
||||
MornyCoeur.extra exec new SendSticker(
|
||||
event.message.chat.id,
|
||||
TelegramStickers ID_PROGYNOVA
|
||||
@ -55,7 +55,7 @@ object 喵呜 {
|
||||
}
|
||||
}
|
||||
|
||||
private def replyingSet (event: Update, whileRec: String, whileNew: String): Unit = {
|
||||
private def replyingSet (whileRec: String, whileNew: String)(using event: Update): Unit = {
|
||||
val isNew = event.message.replyToMessage == null;
|
||||
val target = if (isNew) event.message else event.message.replyToMessage
|
||||
MornyCoeur.extra exec new SendMessage(
|
||||
|
@ -8,10 +8,10 @@ import com.pengrad.telegrambot.request.SendMessage
|
||||
|
||||
object 私わね extends ISimpleCommand {
|
||||
|
||||
override def getName: String = "me"
|
||||
override def getAliases: Array[String] = Array()
|
||||
override val name: String = "me"
|
||||
override val aliases: Array[ICommandAlias] | Null = null
|
||||
|
||||
override def execute (command: InputCommand, event: Update): Unit = {
|
||||
override def execute (using command: InputCommand, event: Update): Unit = {
|
||||
|
||||
if (probabilityTrue(521)) {
|
||||
val text = "/打假"
|
||||
|
@ -0,0 +1,27 @@
|
||||
package cc.sukazyo.cono.morny.bot.event
|
||||
|
||||
import cc.sukazyo.cono.morny.bot.api.EventListenerManager
|
||||
|
||||
object MornyEventListeners {
|
||||
|
||||
def registerAllEvents(): Unit = {
|
||||
|
||||
EventListenerManager.register(
|
||||
// ACTIVITY_RECORDER
|
||||
OnUpdateTimestampOffsetLock,
|
||||
// KUOHUANHUAN_NEED_SLEEP
|
||||
OnTelegramCommand,
|
||||
OnUniMeowTrigger,
|
||||
OnUserRandom,
|
||||
OnQuestionMarkReply,
|
||||
OnUserSlashAction,
|
||||
OnInlineQuery,
|
||||
OnCallMe,
|
||||
OnCallMsgSend,
|
||||
OnMedicationNotifyApply,
|
||||
OnEventHackHandle
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -15,7 +15,7 @@ object OnCallMe extends EventListener {
|
||||
|
||||
private val me = MornyCoeur.config.trustedMaster
|
||||
|
||||
override def onMessage (update: Update): Boolean = {
|
||||
override def onMessage (using update: Update): Boolean = {
|
||||
|
||||
if update.message.text == null then return false
|
||||
if update.message.chat.`type` != (Chat.Type Private) then return false
|
||||
|
@ -0,0 +1,153 @@
|
||||
package cc.sukazyo.cono.morny.bot.event
|
||||
|
||||
import cc.sukazyo.cono.morny.bot.api.EventListener
|
||||
import cc.sukazyo.cono.morny.MornyCoeur
|
||||
import cc.sukazyo.cono.morny.data.TelegramStickers
|
||||
import cc.sukazyo.cono.morny.util.tgapi.formatting.TGToString
|
||||
import com.pengrad.telegrambot.model.{Chat, Message, MessageEntity, Update}
|
||||
import com.pengrad.telegrambot.model.request.ParseMode
|
||||
import com.pengrad.telegrambot.request.{GetChat, SendMessage, SendSticker}
|
||||
|
||||
import scala.collection.mutable.ArrayBuffer
|
||||
import scala.language.postfixOps
|
||||
import scala.util.matching.Regex
|
||||
|
||||
object OnCallMsgSend extends EventListener {
|
||||
|
||||
private val REGEX_MSG_SENDREQ_DATA_HEAD: Regex = "^\\*msg(-?\\d+)(\\*\\S+)?(?:\\n([\\s\\S]+))?$"r
|
||||
|
||||
case class MessageToSend (
|
||||
message: String|Null,
|
||||
entities: Array[MessageEntity]|Null,
|
||||
parseMode: ParseMode|Null,
|
||||
targetId: Long
|
||||
) {
|
||||
def toSendMessage (target_override: Long|Null = null): SendMessage =
|
||||
val useTarget = if target_override == null then targetId else target_override
|
||||
val sendMessage = SendMessage(useTarget, message)
|
||||
if entities ne null then sendMessage.entities(entities:_*)
|
||||
if parseMode ne null then sendMessage.parseMode(parseMode)
|
||||
sendMessage
|
||||
}
|
||||
private object MessageToSend:
|
||||
def from (raw: Message): MessageToSend = {
|
||||
raw.text match
|
||||
case REGEX_MSG_SENDREQ_DATA_HEAD(_target, _parseMode, _body) =>
|
||||
val target = _target toLong
|
||||
val parseMode: ParseMode | Null = _parseMode match
|
||||
case "*markdown" | "*md" | "*m↓" => ParseMode MarkdownV2
|
||||
case "*md1" => ParseMode Markdown
|
||||
case "*html" => ParseMode HTML
|
||||
case _ => null
|
||||
val bodyOffset = "*msg".length + _target.length + (if _parseMode eq null then 0 else _parseMode.length) + 1
|
||||
val entities = ArrayBuffer.empty[MessageEntity]
|
||||
if (raw.entities ne null) for (e <- raw.entities)
|
||||
val _parsed = MessageEntity(e.`type`, e.offset - bodyOffset, e.length)
|
||||
if e.url ne null then _parsed.url(e.url)
|
||||
if e.user ne null then _parsed.user(e.user)
|
||||
if e.language ne null then _parsed.language(e.language)
|
||||
entities += _parsed
|
||||
MessageToSend(_body, entities toArray, parseMode, target)
|
||||
case _ => null
|
||||
}
|
||||
|
||||
override def onMessage (using update: Update): Boolean = {
|
||||
|
||||
val message = update.message
|
||||
|
||||
if message.chat.`type` != Chat.Type.Private then return false
|
||||
if message.text eq null then return false
|
||||
if !(message.text startsWith "*msg") then return false
|
||||
|
||||
if (!(MornyCoeur.trustedInstance isTrusted message.from.id))
|
||||
MornyCoeur.extra exec SendSticker(
|
||||
message.chat.id,
|
||||
TelegramStickers ID_403
|
||||
).replyToMessageId(message.messageId)
|
||||
return true
|
||||
|
||||
if (message.text == "*msgsend") {
|
||||
|
||||
if (message.replyToMessage eq null) return answer404
|
||||
val messageToSend = MessageToSend from message.replyToMessage
|
||||
if ((messageToSend eq null) || (messageToSend.message eq null)) return answer404
|
||||
val sendResponse = MornyCoeur.getAccount execute messageToSend.toSendMessage()
|
||||
|
||||
if (sendResponse isOk) {
|
||||
MornyCoeur.extra exec SendSticker(
|
||||
update.message.chat.id,
|
||||
TelegramStickers ID_SENT
|
||||
).replyToMessageId(update.message.messageId)
|
||||
} else {
|
||||
MornyCoeur.extra exec SendMessage(
|
||||
update.message.chat.id,
|
||||
// language=html
|
||||
s"""<b><u>${sendResponse.errorCode} FAILED</u></b>
|
||||
|<code>${sendResponse.description}</code>"""
|
||||
.stripMargin
|
||||
).replyToMessageId(update.message.messageId).parseMode(ParseMode HTML)
|
||||
}
|
||||
|
||||
return true
|
||||
|
||||
}
|
||||
|
||||
val messageToSend: MessageToSend =
|
||||
val raw: Message =
|
||||
if (message.text == "*msg")
|
||||
if message.replyToMessage eq null then return answer404
|
||||
else message.replyToMessage
|
||||
else if (message.text startsWith "*msg")
|
||||
message
|
||||
else return answer404
|
||||
val _toSend = MessageToSend from raw
|
||||
if _toSend eq null then return answer404
|
||||
else _toSend
|
||||
|
||||
val targetChatResponse = MornyCoeur.getAccount execute GetChat(messageToSend.targetId)
|
||||
if (targetChatResponse isOk) {
|
||||
def getChatDescriptionHTML (chat: Chat): String =
|
||||
import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h
|
||||
val _c = TGToString as chat
|
||||
// language=html
|
||||
s"""<i><u>${h(chat.id toString)}</u>@${h(chat.`type`.name)}</i>${if (chat.`type` != Chat.Type.Private) ":::" else ""}
|
||||
|${_c getTypeTag} <b>${h(_c getSafeName)}</b> ${_c getSafeLinkHTML}"""
|
||||
.stripMargin
|
||||
MornyCoeur.extra exec SendMessage(
|
||||
update.message.chat.id,
|
||||
getChatDescriptionHTML(targetChatResponse.chat)
|
||||
).parseMode(ParseMode HTML).replyToMessageId(update.message.messageId)
|
||||
} else {
|
||||
MornyCoeur.extra exec SendMessage(
|
||||
update.message.chat.id,
|
||||
// language=html
|
||||
s"""<b><u>${targetChatResponse.errorCode} FAILED</u></b>
|
||||
|<code>${targetChatResponse.description}</code>"""
|
||||
.stripMargin
|
||||
).parseMode(ParseMode HTML).replyToMessageId(update.message.messageId)
|
||||
}
|
||||
|
||||
if messageToSend.message eq null then return true
|
||||
val testSendResponse = MornyCoeur.getAccount execute messageToSend.toSendMessage(update.message.chat.id)
|
||||
.replyToMessageId(update.message.messageId)
|
||||
if (!(testSendResponse isOk))
|
||||
MornyCoeur.extra exec SendMessage(
|
||||
update.message.chat.id,
|
||||
// language=html
|
||||
s"""<b><u>${testSendResponse.errorCode}</u> FAILED</b>
|
||||
|<code>${testSendResponse.description}</code>"""
|
||||
.stripMargin
|
||||
).parseMode(ParseMode HTML).replyToMessageId(update.message.messageId)
|
||||
|
||||
true
|
||||
|
||||
}
|
||||
|
||||
private def answer404 (using update: Update): Boolean =
|
||||
MornyCoeur.extra exec SendSticker(
|
||||
update.message.chat.id,
|
||||
TelegramStickers ID_404
|
||||
).replyToMessageId(update.message.messageId)
|
||||
true
|
||||
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
package cc.sukazyo.cono.morny.bot.event
|
||||
|
||||
import cc.sukazyo.cono.morny.bot.api.EventListener
|
||||
|
||||
import scala.collection.mutable
|
||||
import cc.sukazyo.cono.morny.Log.logger
|
||||
import cc.sukazyo.cono.morny.MornyCoeur
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.pengrad.telegrambot.model.Update
|
||||
import com.pengrad.telegrambot.model.request.ParseMode
|
||||
import com.pengrad.telegrambot.request.SendMessage
|
||||
|
||||
import scala.language.postfixOps
|
||||
|
||||
object OnEventHackHandle extends EventListener {
|
||||
|
||||
private case class Hacker (from_chat: Long, from_message: Long):
|
||||
override def toString: String = s"$from_chat/$from_message"
|
||||
enum HackType:
|
||||
case USER
|
||||
case GROUP
|
||||
case ANY
|
||||
|
||||
private val hackers = mutable.HashMap.empty[String, Hacker]
|
||||
|
||||
def registerHack (from_message: Long, from_user: Long, from_chat: Long, t: HackType): Unit =
|
||||
val record = t match
|
||||
case HackType.USER => s"(($from_user))"
|
||||
case HackType.GROUP => s"{{$from_chat}}"
|
||||
case HackType.ANY => "[[]]"
|
||||
hackers += (record -> Hacker(from_chat, from_message))
|
||||
logger debug s"add hacker track $record"
|
||||
|
||||
private def onEventHacked (chat: Long, fromUser: Long)(using update: Update): Boolean = {
|
||||
logger debug s"got event signed {{$chat}}(($fromUser))"
|
||||
val x: Hacker =
|
||||
if hackers contains s"(($fromUser))" then (hackers remove s"(($fromUser))")get
|
||||
else if hackers contains s"{{$chat}}" then (hackers remove s"{{$chat}}")get
|
||||
else if hackers contains "[[]]" then (hackers remove "[[]]")get
|
||||
else return false
|
||||
logger debug s"hacked event by $x"
|
||||
import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml as h
|
||||
MornyCoeur.extra exec SendMessage(
|
||||
x.from_chat,
|
||||
// language=html
|
||||
s"<code>${h(GsonBuilder().setPrettyPrinting().create.toJson(update))}</code>"
|
||||
).parseMode(ParseMode HTML).replyToMessageId(x.from_message toInt)
|
||||
true
|
||||
}
|
||||
|
||||
override def onMessage (using update: Update): Boolean =
|
||||
onEventHacked(update.message.chat.id, update.message.from.id)
|
||||
override def onEditedMessage (using update: Update): Boolean =
|
||||
onEventHacked(update.editedMessage.chat.id, update.editedMessage.from.id)
|
||||
override def onChannelPost (using update: Update): Boolean =
|
||||
onEventHacked(update.channelPost.chat.id, update.channelPost.from.id)
|
||||
override def onEditedChannelPost (using update: Update): Boolean =
|
||||
onEventHacked(update.editedChannelPost.chat.id, update.editedChannelPost.from.id)
|
||||
override def onInlineQuery (using update: Update): Boolean =
|
||||
onEventHacked(0, update.inlineQuery.from.id)
|
||||
override def onChosenInlineResult (using update: Update): Boolean =
|
||||
onEventHacked(0, update.chosenInlineResult.from.id)
|
||||
override def onCallbackQuery (using update: Update): Boolean =
|
||||
onEventHacked(0, update.callbackQuery.from.id)
|
||||
override def onShippingQuery (using update: Update): Boolean =
|
||||
onEventHacked(0, update.shippingQuery.from.id)
|
||||
override def onPreCheckoutQuery (using update: Update): Boolean =
|
||||
onEventHacked(0, update.preCheckoutQuery.from.id)
|
||||
override def onPoll (using update: Update): Boolean =
|
||||
onEventHacked(0, 0)
|
||||
override def onPollAnswer (using update: Update): Boolean =
|
||||
onEventHacked(0, update.pollAnswer.user.id)
|
||||
override def onMyChatMemberUpdated (using update: Update): Boolean =
|
||||
onEventHacked(update.myChatMember.chat.id, update.myChatMember.from.id)
|
||||
override def onChatMemberUpdated (using update: Update): Boolean =
|
||||
onEventHacked(update.chatMember.chat.id, update.chatMember.from.id)
|
||||
override def onChatJoinRequest (using update: Update): Boolean =
|
||||
onEventHacked(update.chatJoinRequest.chat.id, update.chatJoinRequest.from.id)
|
||||
|
||||
}
|
@ -1,7 +1,8 @@
|
||||
package cc.sukazyo.cono.morny.bot.event
|
||||
|
||||
import cc.sukazyo.cono.morny.MornyCoeur
|
||||
import cc.sukazyo.cono.morny.bot.api.{EventListener, InlineQueryUnit}
|
||||
import cc.sukazyo.cono.morny.bot.api.EventListener
|
||||
import cc.sukazyo.cono.morny.bot.query.InlineQueryUnit
|
||||
import com.pengrad.telegrambot.model.Update
|
||||
import com.pengrad.telegrambot.model.request.InlineQueryResult
|
||||
import com.pengrad.telegrambot.request.AnswerInlineQuery
|
||||
@ -12,12 +13,12 @@ import scala.reflect.ClassTag
|
||||
|
||||
object OnInlineQuery extends EventListener {
|
||||
|
||||
override def onInlineQuery (update: Update): Boolean = {
|
||||
override def onInlineQuery (using update: Update): Boolean = {
|
||||
|
||||
val results: List[InlineQueryUnit[_]] = MornyCoeur.queryManager query update
|
||||
|
||||
var cacheTime = Int.MaxValue
|
||||
var isPersonal = InlineQueryUnit.DEFAULT_INLINE_PERSONAL_RESP
|
||||
var isPersonal = InlineQueryUnit.defaults.IS_PERSONAL
|
||||
val resultAnswers = ListBuffer[InlineQueryResult[_]]()
|
||||
for (r <- results) {
|
||||
if (cacheTime > r.cacheTime) cacheTime = r.cacheTime
|
||||
|
@ -0,0 +1,21 @@
|
||||
package cc.sukazyo.cono.morny.bot.event
|
||||
|
||||
import cc.sukazyo.cono.morny.bot.api.EventListener
|
||||
import cc.sukazyo.cono.morny.MornyCoeur
|
||||
import cc.sukazyo.cono.morny.daemon.MornyDaemons
|
||||
import com.pengrad.telegrambot.model.{Message, Update}
|
||||
|
||||
object OnMedicationNotifyApply extends EventListener {
|
||||
|
||||
override def onEditedMessage (using event: Update): Boolean =
|
||||
editedMessageProcess(event.editedMessage)
|
||||
override def onEditedChannelPost (using event: Update): Boolean =
|
||||
editedMessageProcess(event.editedChannelPost)
|
||||
|
||||
private def editedMessageProcess (edited: Message): Boolean = {
|
||||
if edited.chat.id != MornyCoeur.config.medicationNotifyToChat then return false
|
||||
MornyDaemons.medicationTimerInstance.refreshNotificationWrite(edited)
|
||||
true
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package cc.sukazyo.cono.morny.bot.event
|
||||
|
||||
import cc.sukazyo.cono.morny.bot.api.EventListener
|
||||
import cc.sukazyo.cono.morny.MornyCoeur
|
||||
import com.pengrad.telegrambot.model.Update
|
||||
import com.pengrad.telegrambot.request.SendMessage
|
||||
|
||||
import scala.language.postfixOps
|
||||
|
||||
object OnQuestionMarkReply extends EventListener {
|
||||
|
||||
private def QUESTION_MARKS = Set('?', '?', '¿', '⁈', '⁇', '‽', '❔', '❓')
|
||||
|
||||
override def onMessage (using event: Update): Boolean = {
|
||||
|
||||
if event.message.text eq null then return false
|
||||
|
||||
import cc.sukazyo.cono.morny.util.CommonRandom.probabilityTrue
|
||||
if !probabilityTrue(8) then return false
|
||||
for (c <- event.message.text toCharArray)
|
||||
if !(QUESTION_MARKS contains c) then return false
|
||||
|
||||
MornyCoeur.extra exec SendMessage(
|
||||
event.message.chat.id, event.message.text
|
||||
).replyToMessageId(event.message.messageId)
|
||||
true
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package cc.sukazyo.cono.morny.bot.event
|
||||
|
||||
import cc.sukazyo.cono.morny.bot.api.EventListener
|
||||
import cc.sukazyo.cono.morny.util.tgapi.InputCommand
|
||||
import com.pengrad.telegrambot.model.{Message, Update}
|
||||
import cc.sukazyo.cono.morny.Log.logger
|
||||
import cc.sukazyo.cono.morny.MornyCoeur
|
||||
import cc.sukazyo.cono.morny.bot.command.MornyCommands
|
||||
|
||||
object OnTelegramCommand extends EventListener {
|
||||
|
||||
override def onMessage (using update: Update): Boolean = {
|
||||
|
||||
def _isCommandMessage(message: Message): Boolean =
|
||||
if message.text eq null then false
|
||||
else if !(message.text startsWith "/") then false
|
||||
else if message.text startsWith "/ " then false
|
||||
else true
|
||||
|
||||
if !_isCommandMessage(update.message) then return false
|
||||
val inputCommand = InputCommand(update.message.text drop 1)
|
||||
if (!(inputCommand.getCommand matches "^\\w+$"))
|
||||
logger debug "not command"
|
||||
false
|
||||
else if ((inputCommand.getTarget ne null) && (inputCommand.getTarget ne MornyCoeur.getUsername))
|
||||
logger debug "not morny command"
|
||||
false
|
||||
else
|
||||
logger debug "is command"
|
||||
MornyCommands.execute(using inputCommand)
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package cc.sukazyo.cono.morny.bot.event
|
||||
|
||||
import cc.sukazyo.cono.morny.bot.api.EventListener
|
||||
import cc.sukazyo.cono.morny.bot.command.MornyCommands
|
||||
import cc.sukazyo.cono.morny.util.tgapi.InputCommand
|
||||
import com.pengrad.telegrambot.model.Update
|
||||
|
||||
object OnUniMeowTrigger extends EventListener {
|
||||
|
||||
override def onMessage (using update: Update): Boolean = {
|
||||
|
||||
if update.message.text eq null then return false
|
||||
var ok = false
|
||||
for ((name, command) <- MornyCommands.commands_uni)
|
||||
val _name = "/"+name
|
||||
if (_name == update.message.text)
|
||||
command.execute(using InputCommand(_name))
|
||||
ok = true
|
||||
ok
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package cc.sukazyo.cono.morny.bot.event
|
||||
|
||||
import cc.sukazyo.cono.morny.bot.api.EventListener
|
||||
import cc.sukazyo.cono.morny.MornyCoeur
|
||||
import com.pengrad.telegrambot.model.Update
|
||||
|
||||
object OnUpdateTimestampOffsetLock extends EventListener {
|
||||
|
||||
private def isOutdated (timestamp: Int): Boolean =
|
||||
timestamp < (MornyCoeur.config.eventOutdatedTimestamp/1000)
|
||||
|
||||
override def onMessage (using update: Update): Boolean = isOutdated(update.message.date)
|
||||
override def onEditedMessage (using update: Update): Boolean = isOutdated(update.editedMessage.date)
|
||||
override def onChannelPost (using update: Update): Boolean = isOutdated(update.channelPost.date)
|
||||
override def onEditedChannelPost (using update: Update): Boolean = isOutdated(update.editedChannelPost.date)
|
||||
|
||||
}
|
@ -12,7 +12,7 @@ object OnUserRandom extends EventListener {
|
||||
private val USER_OR_QUERY = "(.+)(?:还是|or)(.+)"r
|
||||
private val USER_IF_QUERY = "(.+)[吗?|?]+$"r
|
||||
|
||||
override def onMessage(update: Update): Boolean = {
|
||||
override def onMessage(using update: Update): Boolean = {
|
||||
|
||||
if update.message.text == null then return false
|
||||
if update.message.text startsWith "/" then return false
|
||||
|
@ -15,9 +15,9 @@ object OnUserSlashAction extends EventListener {
|
||||
|
||||
private val TG_FORMAT = "^\\w+(@\\w+)?$"r
|
||||
|
||||
override def onMessage (update: Update): Boolean = {
|
||||
override def onMessage (using update: Update): Boolean = {
|
||||
|
||||
val text = update.message.text;
|
||||
val text = update.message.text
|
||||
if text == null then return false
|
||||
|
||||
if (text startsWith "/") {
|
||||
@ -31,6 +31,7 @@ object OnUserSlashAction extends EventListener {
|
||||
case TG_FORMAT(_) =>
|
||||
return false
|
||||
case x if x contains "/" => return false
|
||||
case _ =>
|
||||
|
||||
val isHardParse = actions(0) isBlank
|
||||
def hp_len(i: Int) = if isHardParse then i+1 else i
|
||||
@ -39,7 +40,7 @@ object OnUserSlashAction extends EventListener {
|
||||
val hasObject = actions.length != hp_len(1)
|
||||
val v_object =
|
||||
if hasObject then
|
||||
actions slice(hp_len(1), actions.length) mkString(" ")
|
||||
actions slice(hp_len(1), actions.length) mkString " "
|
||||
else ""
|
||||
val origin = update.message
|
||||
val target =
|
||||
|
@ -1,7 +1,6 @@
|
||||
package cc.sukazyo.cono.morny.bot.query
|
||||
|
||||
import javax.annotation.Nullable
|
||||
import cc.sukazyo.cono.morny.bot.api.InlineQueryUnit
|
||||
import com.pengrad.telegrambot.model.Update
|
||||
|
||||
trait ITelegramQuery {
|
||||
|
@ -0,0 +1,27 @@
|
||||
package cc.sukazyo.cono.morny.bot.query
|
||||
|
||||
import cc.sukazyo.cono.morny.bot.query.InlineQueryUnit.defaults
|
||||
import com.pengrad.telegrambot.model.request.InlineQueryResult
|
||||
|
||||
object InlineQueryUnit {
|
||||
|
||||
object defaults:
|
||||
val CACHE_TIME = 300
|
||||
val IS_PERSONAL = false
|
||||
|
||||
}
|
||||
|
||||
class InlineQueryUnit[T <: InlineQueryResult[T]](val result: T) {
|
||||
|
||||
var cacheTime: Int = defaults.CACHE_TIME
|
||||
var isPersonal: Boolean = defaults.IS_PERSONAL
|
||||
|
||||
def cacheTime (v: Int): InlineQueryUnit[T] =
|
||||
this.cacheTime = v
|
||||
this
|
||||
|
||||
def isPersonal (v: Boolean): InlineQueryUnit[T] =
|
||||
this.isPersonal = v
|
||||
this
|
||||
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
package cc.sukazyo.cono.morny.bot.query
|
||||
|
||||
import cc.sukazyo.cono.morny.bot.api.InlineQueryUnit
|
||||
import cc.sukazyo.cono.morny.bot.query
|
||||
import com.pengrad.telegrambot.model.Update
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
package cc.sukazyo.cono.morny.bot.query
|
||||
|
||||
import cc.sukazyo.cono.morny.bot.api.InlineQueryUnit
|
||||
import cc.sukazyo.cono.morny.util.tgapi.formatting.NamedUtils.inlineIds
|
||||
import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramUserInformation
|
||||
import com.pengrad.telegrambot.model.Update
|
||||
|
@ -1,5 +1,4 @@
|
||||
package cc.sukazyo.cono.morny.bot.query
|
||||
import cc.sukazyo.cono.morny.bot.api.InlineQueryUnit
|
||||
import cc.sukazyo.cono.morny.util.tgapi.formatting.NamedUtils.inlineIds
|
||||
import com.pengrad.telegrambot.model.Update
|
||||
import com.pengrad.telegrambot.model.request.{InlineQueryResultArticle, InputTextMessageContent}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package cc.sukazyo.cono.morny.bot.query
|
||||
|
||||
import cc.sukazyo.cono.morny.Log.logger
|
||||
import cc.sukazyo.cono.morny.bot.api.InlineQueryUnit
|
||||
import cc.sukazyo.cono.morny.util.BiliTool
|
||||
import cc.sukazyo.cono.morny.util.tgapi.formatting.NamedUtils.inlineIds
|
||||
import com.pengrad.telegrambot.model.Update
|
||||
|
@ -1,6 +1,5 @@
|
||||
package cc.sukazyo.cono.morny.bot.query
|
||||
|
||||
import cc.sukazyo.cono.morny.bot.api.InlineQueryUnit
|
||||
import com.pengrad.telegrambot.model.Update
|
||||
import com.pengrad.telegrambot.model.request.InlineQueryResultArticle
|
||||
|
||||
|
17
src/main/scala/cc/sukazyo/cono/morny/data/MornyJrrp.scala
Normal file
17
src/main/scala/cc/sukazyo/cono/morny/data/MornyJrrp.scala
Normal file
@ -0,0 +1,17 @@
|
||||
package cc.sukazyo.cono.morny.data
|
||||
|
||||
import com.pengrad.telegrambot.model.User
|
||||
|
||||
import scala.language.postfixOps
|
||||
|
||||
object MornyJrrp {
|
||||
|
||||
def jrrp_of_telegramUser (user: User, timestamp: Long): Double =
|
||||
jrrp_v_xmomi(user.id, timestamp/(1000*60*60*24)) * 100.0
|
||||
|
||||
private def jrrp_v_xmomi (identifier: Long, dayStamp: Long): Double =
|
||||
import cc.sukazyo.cono.morny.util.CommonConvert.byteArrayToHex
|
||||
import cc.sukazyo.cono.morny.util.CommonEncrypt.hashMd5
|
||||
(java.lang.Long parseLong byteArrayToHex(hashMd5(s"$identifier@$dayStamp")).substring(0, 4)) / (0xffff toDouble)
|
||||
|
||||
}
|
37
src/main/scala/cc/sukazyo/cono/morny/data/NbnhhshQuery.scala
Normal file
37
src/main/scala/cc/sukazyo/cono/morny/data/NbnhhshQuery.scala
Normal file
@ -0,0 +1,37 @@
|
||||
package cc.sukazyo.cono.morny.data
|
||||
|
||||
import cc.sukazyo.cono.morny.util.OkHttpPublic.MediaTypes
|
||||
import com.google.gson.Gson
|
||||
import okhttp3.{OkHttpClient, Request, RequestBody, ResponseBody}
|
||||
|
||||
import java.io.IOException
|
||||
import scala.util.Using
|
||||
|
||||
object NbnhhshQuery {
|
||||
|
||||
case class Word (name: String, trans: Array[String], inputting: Array[String])
|
||||
case class GuessResult (words: Array[Word])
|
||||
|
||||
private case class GuessRequest (text: String)
|
||||
|
||||
private val API_URL = "https://lab.magiconch.com/api/nbnhhsh/"
|
||||
private val API_GUESS_METHOD = "guess/"
|
||||
|
||||
private val httpClient = OkHttpClient()
|
||||
|
||||
@throws[IOException]
|
||||
def sendGuess (text: String): GuessResult = {
|
||||
val requestJsonText = Gson().toJson(GuessRequest(text))
|
||||
val request = Request.Builder()
|
||||
.url(API_URL + API_GUESS_METHOD)
|
||||
.post(RequestBody.create(requestJsonText, MediaTypes.JSON))
|
||||
.build
|
||||
Using (httpClient.newCall(request).execute) { response =>
|
||||
val body = response.body
|
||||
if body eq null then throw IOException("Nbnhhsh Request: body is null.")
|
||||
val x = s"{ 'words': ${body.string} }"
|
||||
Gson().fromJson(x, classOf[GuessResult])
|
||||
}.get
|
||||
}
|
||||
|
||||
}
|
@ -30,12 +30,11 @@ object IP186QueryHandler {
|
||||
@throws[IOException]
|
||||
private def commonQuery (requestUrl: String, queryParam: String): IP186Response = {
|
||||
val request = Request.Builder().url(requestUrl + "?" + queryParam).build
|
||||
var _body_string: String|Null = null
|
||||
Using ((httpClient newCall request) execute) { response =>
|
||||
if response.body ne null then _body_string = response.body.string
|
||||
}
|
||||
if _body_string eq null then throw IOException("Response of ip186: body is empty!")
|
||||
IP186Response(requestUrl, _body_string)
|
||||
val _body = response.body
|
||||
if _body eq null then throw IOException("Response of ip186: body is empty!")
|
||||
IP186Response(requestUrl, _body.string)
|
||||
}.get
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user