diff --git a/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/bot/BaseAbilityBot.java b/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/bot/BaseAbilityBot.java index ab2dd1b5..e8c53d6e 100644 --- a/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/bot/BaseAbilityBot.java +++ b/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/bot/BaseAbilityBot.java @@ -27,6 +27,7 @@ import org.telegram.telegrambots.meta.api.objects.User; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.*; +import java.util.concurrent.Callable; import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Predicate; @@ -557,15 +558,25 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability boolean filterReply(Update update) { return replies.stream() - .filter(reply -> reply.isOkFor(update)) - .map(reply -> { + .filter(reply -> runSilently(() -> reply.isOkFor(update), reply.name())) + .map(reply -> runSilently(() -> { reply.actOn(update); updateReplyStats(reply); return false; - }) + }, reply.name())) .reduce(true, Boolean::logicalAnd); } + boolean runSilently(Callable callable, String name) { + try { + return callable.call(); + } catch(Exception ex) { + log.error(format("Reply [%s] failed to check for conditions. " + + "Make sure you're safeguarding against all possible updates.", name)); + } + return false; + } + boolean checkMessageFlags(Trio trio) { Ability ability = trio.b(); Update update = trio.a(); diff --git a/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/bot/ReplyFlowTest.java b/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/bot/ReplyFlowTest.java index e1884e66..b117ab7a 100644 --- a/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/bot/ReplyFlowTest.java +++ b/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/bot/ReplyFlowTest.java @@ -146,10 +146,8 @@ public class ReplyFlowTest { @Test void replyFlowsPertainNames() { - Update update1 = mockFullUpdate(bot, USER, "one"); - long chatId = getChatId(update1); Set replyNames = bot.replies().stream().map(Reply::name).collect(Collectors.toSet()); - replyNames.containsAll(newHashSet("FIRST", "SECOND")); + assertTrue(replyNames.containsAll(newHashSet("FIRST", "SECOND"))); } public static class ReplyFlowBot extends AbilityBot { @@ -183,6 +181,16 @@ public class ReplyFlowTest { .build(); } + public Reply errantReply() { + return Reply.of( + upd -> { + throw new RuntimeException("Throwing an exception inside the update consumer"); + }, + upd -> { + throw new RuntimeException("Throwing an exception inside the reply conditions (flags)"); + }); + } + public Ability replyFlowsWithAbility() { Reply replyWithVk = ReplyFlow.builder(db, 2) .enableStats("SECOND")