*/
@@ -166,6 +176,7 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability
return replies;
}
+
/**
* This method contains the stream of actions that are applied on any update.
*
@@ -183,6 +194,7 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability
.filter(this::checkBlacklist)
.map(this::addUser)
.filter(this::filterReply)
+ .filter(this::hasUser)
.map(this::getAbility)
.filter(this::validateAbility)
.filter(this::checkPrivacy)
@@ -191,8 +203,12 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability
.filter(this::checkMessageFlags)
.map(this::getContext)
.map(this::consumeUpdate)
+ .map(this::updateStats)
.forEach(this::postConsumption);
+ // Commit to DB now after all the actions have been dealt
+ db.commit();
+
long processingTime = System.currentTimeMillis() - millisStarted;
log.info(format("[%s] Processing of update [%s] ended at %s%n---> Processing time: [%d ms] <---%n", botUsername, update.getUpdateId(), now(), processingTime));
}
@@ -275,6 +291,19 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability
}
}
+ private void initStats() {
+ Set enabledStats = Stream.concat(
+ replies.stream().filter(Reply::statsEnabled).map(Reply::name),
+ abilities.entrySet().stream()
+ .filter(entry -> entry.getValue().statsEnabled())
+ .map(Map.Entry::getKey)).collect(toSet());
+ stats = db.getMap(STATS);
+ Set toBeRemoved = difference(stats.keySet(), enabledStats);
+ toBeRemoved.forEach(stats::remove);
+ enabledStats.forEach(abName -> stats.computeIfAbsent(abName,
+ name -> createStats(abName, 0)));
+ }
+
/**
* @param clazz the type to be tested
* @return a predicate testing the return type of the method corresponding to the class parameter
@@ -344,6 +373,26 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability
return pair;
}
+ Pair updateStats(Pair pair) {
+ Ability ab = pair.b();
+ if (ab.statsEnabled()) {
+ updateStats(pair.b().name());
+ }
+ return pair;
+ }
+
+ private void updateReplyStats(Reply reply) {
+ if (reply.statsEnabled()) {
+ updateStats(reply.name());
+ }
+ }
+
+ void updateStats(String name) {
+ Stats statsObj = stats.get(name);
+ statsObj.hit();
+ stats.put(name, statsObj);
+ }
+
Pair getContext(Trio trio) {
Update update = trio.a();
User user = AbilityUtils.getUser(update);
@@ -465,6 +514,10 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability
Update addUser(Update update) {
User endUser = AbilityUtils.getUser(update);
+ if (endUser.equals(EMPTY_USER)) {
+ // Can't add an empty user, return the update as is
+ return update;
+ }
users().compute(endUser.getId(), (id, user) -> {
if (user == null) {
@@ -480,10 +533,15 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability
return user;
});
- db.commit();
return update;
}
+ private boolean hasUser(Update update) {
+ // Valid updates without users should return an empty user
+ // Updates that are not recognized by the getUser method will throw an exception
+ return !AbilityUtils.getUser(update).equals(EMPTY_USER);
+ }
+
private void updateUserId(User oldUser, User newUser) {
if (oldUser != null && oldUser.getUserName() != null) {
// Remove old username -> ID
@@ -501,6 +559,7 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability
.filter(reply -> reply.isOkFor(update))
.map(reply -> {
reply.actOn(update);
+ updateReplyStats(reply);
return false;
})
.reduce(true, Boolean::logicalAnd);
diff --git a/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/bot/DefaultAbilities.java b/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/bot/DefaultAbilities.java
index 3405cfb8..6e1139bb 100644
--- a/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/bot/DefaultAbilities.java
+++ b/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/bot/DefaultAbilities.java
@@ -26,6 +26,7 @@ import java.io.PrintStream;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
+import java.util.StringJoiner;
import static com.google.common.base.Strings.isNullOrEmpty;
import static com.google.common.collect.MultimapBuilder.hashKeys;
@@ -60,7 +61,6 @@ import static org.telegram.abilitybots.api.util.AbilityMessageCodes.ABILITY_UNBA
import static org.telegram.abilitybots.api.util.AbilityMessageCodes.ABILITY_UNBAN_SUCCESS;
import static org.telegram.abilitybots.api.util.AbilityMessageCodes.USER_NOT_FOUND;
import static org.telegram.abilitybots.api.util.AbilityUtils.addTag;
-import static org.telegram.abilitybots.api.util.AbilityUtils.commitTo;
import static org.telegram.abilitybots.api.util.AbilityUtils.escape;
import static org.telegram.abilitybots.api.util.AbilityUtils.getLocalizedMessage;
import static org.telegram.abilitybots.api.util.AbilityUtils.shortName;
@@ -77,6 +77,7 @@ public final class DefaultAbilities implements AbilityExtension {
public static final String RECOVER = "recover";
public static final String COMMANDS = "commands";
public static final String REPORT = "report";
+ public static final String STATS = "stats";
private static final Logger log = LoggerFactory.getLogger(DefaultAbilities.class);
private final BaseAbilityBot bot;
@@ -180,6 +181,26 @@ public final class DefaultAbilities implements AbilityExtension {
.build();
}
+ /**
+ * @return the ability to report statistics for abilities and replies.
+ */
+ public Ability reportStats() {
+ return builder()
+ .name(STATS)
+ .locality(ALL)
+ .privacy(ADMIN)
+ .input(0)
+ .action(ctx -> {
+ String stats = bot.stats().entrySet().stream()
+ .map(entry -> String.format("%s: %d", entry.getKey(), entry.getValue().hits()))
+ .reduce(new StringJoiner("\n"), StringJoiner::add, StringJoiner::merge)
+ .toString();
+
+ bot.silent.send(stats, ctx.chatId());
+ })
+ .build();
+ }
+
/**
* This backup ability returns the object defined by {@link DBContext#backup()} as a message document.
*
@@ -213,6 +234,7 @@ public final class DefaultAbilities implements AbilityExtension {
.build();
}
+
/**
* Recovers the bot database using {@link DBContext#recover(Object)}.
*
@@ -288,7 +310,6 @@ public final class DefaultAbilities implements AbilityExtension {
sendMd(ABILITY_BAN_SUCCESS, ctx, escape(bannedUser));
}
})
- .post(commitTo(bot.db))
.build();
}
@@ -315,7 +336,6 @@ public final class DefaultAbilities implements AbilityExtension {
bot.silent.sendMd(getLocalizedMessage(ABILITY_UNBAN_SUCCESS, ctx.user().getLanguageCode(), escape(username)), ctx.chatId());
}
})
- .post(commitTo(bot.db))
.build();
}
@@ -339,7 +359,7 @@ public final class DefaultAbilities implements AbilityExtension {
admins.add(userId);
sendMd(ABILITY_PROMOTE_SUCCESS, ctx, escape(username));
}
- }).post(commitTo(bot.db))
+ })
.build();
}
@@ -363,7 +383,6 @@ public final class DefaultAbilities implements AbilityExtension {
sendMd(ABILITY_DEMOTE_FAIL, ctx, escape(username));
}
})
- .post(commitTo(bot.db))
.build();
}
@@ -389,7 +408,6 @@ public final class DefaultAbilities implements AbilityExtension {
send(ABILITY_CLAIM_SUCCESS, ctx);
}
})
- .post(commitTo(bot.db))
.build();
}
diff --git a/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/objects/Ability.java b/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/objects/Ability.java
index f9ddcd71..0b6691bb 100644
--- a/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/objects/Ability.java
+++ b/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/objects/Ability.java
@@ -42,13 +42,14 @@ public final class Ability {
private final Locality locality;
private final Privacy privacy;
private final int argNum;
+ private final boolean statsEnabled;
private final Consumer action;
private final Consumer postAction;
private final List replies;
private final List> flags;
@SafeVarargs
- private Ability(String name, String info, Locality locality, Privacy privacy, int argNum, Consumer action, Consumer postAction, List replies, Predicate... flags) {
+ private Ability(String name, String info, Locality locality, Privacy privacy, int argNum, boolean statsEnabled, Consumer action, Consumer postAction, List replies, Predicate... flags) {
checkArgument(!isEmpty(name), "Method name cannot be empty");
checkArgument(!containsWhitespace(name), "Method name cannot contain spaces");
checkArgument(isAlphanumeric(name), "Method name can only be alpha-numeric", name);
@@ -70,6 +71,7 @@ public final class Ability {
this.postAction = postAction;
this.replies = replies;
+ this.statsEnabled = statsEnabled;
}
public static AbilityBuilder builder() {
@@ -96,6 +98,10 @@ public final class Ability {
return argNum;
}
+ public boolean statsEnabled() {
+ return statsEnabled;
+ }
+
public Consumer action() {
return action;
}
@@ -147,12 +153,14 @@ public final class Ability {
private Privacy privacy;
private Locality locality;
private int argNum;
+ private boolean statsEnabled;
private Consumer action;
private Consumer postAction;
private List replies;
private Predicate[] flags;
private AbilityBuilder() {
+ statsEnabled = false;
replies = newArrayList();
}
@@ -186,6 +194,11 @@ public final class Ability {
return this;
}
+ public AbilityBuilder enableStats() {
+ statsEnabled = true;
+ return this;
+ }
+
public AbilityBuilder privacy(Privacy privacy) {
this.privacy = privacy;
return this;
@@ -202,6 +215,11 @@ public final class Ability {
return this;
}
+ public final AbilityBuilder reply(Reply reply) {
+ replies.add(reply);
+ return this;
+ }
+
public AbilityBuilder basedOn(Ability ability) {
replies.clear();
replies.addAll(ability.replies());
@@ -216,7 +234,7 @@ public final class Ability {
}
public Ability build() {
- return new Ability(name, info, locality, privacy, argNum, action, postAction, replies, flags);
+ return new Ability(name, info, locality, privacy, argNum, statsEnabled, action, postAction, replies, flags);
}
}
}
diff --git a/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/objects/Flag.java b/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/objects/Flag.java
index 3712dc9a..9930ad7e 100644
--- a/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/objects/Flag.java
+++ b/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/objects/Flag.java
@@ -25,6 +25,10 @@ public enum Flag implements Predicate {
EDITED_MESSAGE(Update::hasEditedMessage),
INLINE_QUERY(Update::hasInlineQuery),
CHOSEN_INLINE_QUERY(Update::hasChosenInlineQuery),
+ SHIPPING_QUERY(Update::hasShippingQuery),
+ PRECHECKOUT_QUERY(Update::hasPreCheckoutQuery),
+ POLL(Update::hasPoll),
+ POLL_ANSWER(Update::hasPollAnswer),
// Message Flags
REPLY(upd -> MESSAGE.test(upd) && upd.getMessage().isReply()),
diff --git a/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/objects/Reply.java b/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/objects/Reply.java
index 6af4c921..e7479489 100644
--- a/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/objects/Reply.java
+++ b/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/objects/Reply.java
@@ -26,12 +26,15 @@ import static java.util.Arrays.asList;
public class Reply {
public final List> conditions;
public final Consumer action;
+ private boolean statsEnabled;
+ private String name;
Reply(List> conditions, Consumer action) {
this.conditions = ImmutableList.>builder()
.addAll(conditions)
.build();
this.action = action;
+ statsEnabled = false;
}
public static Reply of(Consumer action, List> conditions) {
@@ -65,6 +68,20 @@ public class Reply {
return Stream.of(this);
}
+ public Reply enableStats(String name) {
+ this.name = name;
+ statsEnabled = true;
+ return this;
+ }
+
+ public boolean statsEnabled() {
+ return statsEnabled;
+ }
+
+ public String name() {
+ return name;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o)
diff --git a/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/objects/Stats.java b/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/objects/Stats.java
new file mode 100644
index 00000000..43b6b350
--- /dev/null
+++ b/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/objects/Stats.java
@@ -0,0 +1,64 @@
+package org.telegram.abilitybots.api.objects;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects;
+import org.json.JSONPropertyIgnore;
+
+import java.io.Serializable;
+import java.util.Objects;
+
+/**
+ * Basic POJO to track ability and reply hits. The current implementation is NOT thread safe.
+ *
+ * @author Abbas Abou Daya
+ */
+public final class Stats implements Serializable {
+ @JsonProperty
+ private final String name;
+ @JsonProperty
+ private long hits;
+
+ private Stats(String name) {
+ this.name = name;
+ }
+
+ @JsonCreator
+ public static Stats createStats(@JsonProperty("name") String name, @JsonProperty("hits") long hits) {
+ return new Stats(name);
+ }
+
+ public String name() {
+ return name;
+ }
+
+ public long hits() {
+ return hits;
+ }
+
+ public void hit() {
+ hits++;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ Stats that = (Stats) o;
+ return hits == that.hits &&
+ Objects.equals(name, that.name);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name, hits);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("name", name)
+ .add("hits", hits)
+ .toString();
+ }
+}
diff --git a/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/util/AbilityUtils.java b/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/util/AbilityUtils.java
index ec213667..6382f866 100644
--- a/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/util/AbilityUtils.java
+++ b/telegrambots-abilities/src/main/java/org/telegram/abilitybots/api/util/AbilityUtils.java
@@ -24,6 +24,8 @@ import static org.telegram.abilitybots.api.objects.Flag.*;
* Helper and utility methods
*/
public final class AbilityUtils {
+ public static User EMPTY_USER = new User(0, "", false, "", "", "");
+
private AbilityUtils() {
}
@@ -69,6 +71,14 @@ public final class AbilityUtils {
return update.getEditedMessage().getFrom();
} else if (CHOSEN_INLINE_QUERY.test(update)) {
return update.getChosenInlineQuery().getFrom();
+ } else if (SHIPPING_QUERY.test(update)) {
+ return update.getShippingQuery().getFrom();
+ } else if (PRECHECKOUT_QUERY.test(update)) {
+ return update.getPreCheckoutQuery().getFrom();
+ } else if (POLL_ANSWER.test(update)) {
+ return update.getPollAnswer().getUser();
+ } else if (POLL.test(update)) {
+ return EMPTY_USER;
} else {
throw new IllegalStateException("Could not retrieve originating user from update");
}
@@ -140,6 +150,14 @@ public final class AbilityUtils {
return update.getEditedMessage().getChatId();
} else if (CHOSEN_INLINE_QUERY.test(update)) {
return (long) update.getChosenInlineQuery().getFrom().getId();
+ } else if (SHIPPING_QUERY.test(update)) {
+ return (long) update.getShippingQuery().getFrom().getId();
+ } else if (PRECHECKOUT_QUERY.test(update)) {
+ return (long) update.getPreCheckoutQuery().getFrom().getId();
+ } else if (POLL_ANSWER.test(update)) {
+ return (long) update.getPollAnswer().getUser().getId();
+ } else if (POLL.test(update)) {
+ return (long) EMPTY_USER.getId();
} else {
throw new IllegalStateException("Could not retrieve originating chat ID from update");
}
@@ -160,10 +178,8 @@ public final class AbilityUtils {
return update.getEditedChannelPost().isUserMessage();
} else if (EDITED_MESSAGE.test(update)) {
return update.getEditedMessage().isUserMessage();
- } else if (CHOSEN_INLINE_QUERY.test(update) || INLINE_QUERY.test(update)) {
- return true;
} else {
- throw new IllegalStateException("Could not retrieve update context origin (user/group)");
+ return true;
}
}
diff --git a/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/bot/AbilityBotTest.java b/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/bot/AbilityBotTest.java
index 36717ac0..476b3b1e 100644
--- a/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/bot/AbilityBotTest.java
+++ b/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/bot/AbilityBotTest.java
@@ -8,10 +8,12 @@ import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentMatchers;
+import org.mockito.Mockito;
import org.telegram.abilitybots.api.db.DBContext;
import org.telegram.abilitybots.api.objects.*;
import org.telegram.abilitybots.api.sender.MessageSender;
import org.telegram.abilitybots.api.sender.SilentSender;
+import org.telegram.abilitybots.api.util.AbilityUtils;
import org.telegram.abilitybots.api.util.Pair;
import org.telegram.abilitybots.api.util.Trio;
import org.telegram.telegrambots.meta.api.methods.groupadministration.GetChatAdministrators;
@@ -25,6 +27,7 @@ import java.util.Arrays;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
+import java.util.function.Consumer;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Sets.newHashSet;
@@ -38,8 +41,8 @@ import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
import static org.mockito.internal.verification.VerificationModeFactory.times;
import static org.telegram.abilitybots.api.bot.DefaultBot.getDefaultBuilder;
-import static org.telegram.abilitybots.api.bot.TestUtils.*;
import static org.telegram.abilitybots.api.bot.TestUtils.CREATOR;
+import static org.telegram.abilitybots.api.bot.TestUtils.*;
import static org.telegram.abilitybots.api.db.MapDBContext.offlineInstance;
import static org.telegram.abilitybots.api.objects.Flag.DOCUMENT;
import static org.telegram.abilitybots.api.objects.Flag.MESSAGE;
@@ -120,6 +123,49 @@ public class AbilityBotTest {
verify(silent, times(1)).send("reply", USER.getId());
}
+ @Test
+ void canProcessUpdatesWithoutUserInfo() {
+ Update update = mock(Update.class);
+ // At the moment, only poll updates carry no user information
+ when(update.hasPoll()).thenReturn(true);
+
+ bot.onUpdateReceived(update);
+ }
+
+ @Test
+ void getUserHasAllMethodsDefined() {
+ Arrays.stream(Update.class.getMethods())
+ // filter to all these methods of hasXXX (hasPoll, hasMessage, etc...)
+ .filter(method -> method.getName().startsWith("has"))
+ // Gotta filter out hashCode
+ .filter(method -> method.getReturnType().getName().equals("boolean"))
+ .forEach(method -> {
+ Update update = mock(Update.class);
+ try {
+ // Mock the method and make sure it returns true so that it gets processed by the following method
+ when(method.invoke(update)).thenReturn(true);
+ // Call the getUser function, throws an IllegalStateException if there's an update that can't be processed
+ AbilityUtils.getUser(update);
+ } catch (IllegalStateException e) {
+ throw new RuntimeException(
+ format("Found an update variation that is not handled by the getUser util method [%s]", method.getName()), e);
+ } catch (NullPointerException | ReflectiveOperationException e) {
+ // This is fine, the mock isn't complete and we're only
+ // looking for IllegalStateExceptions thrown by the method
+ }
+ });
+ }
+
+ @Test
+ void getChatIdCanHandleAllKindsOfUpdates() {
+ handlesAllUpdates(AbilityUtils::getUser);
+ }
+
+ @Test
+ void getUserCanHandleAllKindsOfUpdates() {
+ handlesAllUpdates(AbilityUtils::getChatId);
+ }
+
@Test
void canBackupDB() throws TelegramApiException {
MessageContext context = defaultContext();
@@ -130,6 +176,30 @@ public class AbilityBotTest {
verify(sender, times(1)).sendDocument(any());
}
+ @Test
+ void canReportStatistics() {
+ MessageContext context = defaultContext();
+
+ defaultAbs.reportStats().action().accept(context);
+
+ verify(silent, times(1)).send("count: 0\nmustreply: 0", GROUP_ID);
+ }
+
+ @Test
+ void canReportUpdatedStatistics() {
+ Update upd1 = mockFullUpdate(bot, CREATOR, "/count 1 2 3 4");
+ bot.onUpdateReceived(upd1);
+ Update upd2 = mockFullUpdate(bot, CREATOR, "must reply");
+ bot.onUpdateReceived(upd2);
+
+ Mockito.reset(silent);
+
+ Update statUpd = mockFullUpdate(bot, CREATOR, "/stats");
+ bot.onUpdateReceived(statUpd);
+
+ verify(silent, times(1)).send("count: 1\nmustreply: 1", CREATOR.getId());
+ }
+
@Test
void canRecoverDB() throws TelegramApiException, IOException {
Update update = mockBackupUpdate();
@@ -553,7 +623,7 @@ public class AbilityBotTest {
defaultAbs.commands().action().accept(creatorCtx);
- String expected = "PUBLIC\n/commands\n/count\n/default - dis iz default command\n/group\n/test\nADMIN\n/admin\n/ban\n/demote\n/promote\n/unban\nCREATOR\n/backup\n/claim\n/recover\n/report";
+ String expected = "PUBLIC\n/commands\n/count\n/default - dis iz default command\n/group\n/test\nADMIN\n/admin\n/ban\n/demote\n/promote\n/stats\n/unban\nCREATOR\n/backup\n/claim\n/recover\n/report";
verify(silent, times(1)).send(expected, GROUP_ID);
}
@@ -574,6 +644,29 @@ public class AbilityBotTest {
verify(silent, times(1)).send(expected, GROUP_ID);
}
+ private void handlesAllUpdates(Consumer utilMethod) {
+ Arrays.stream(Update.class.getMethods())
+ // filter to all these methods of hasXXX (hasPoll, hasMessage, etc...)
+ .filter(method -> method.getName().startsWith("has"))
+ // Gotta filter out hashCode
+ .filter(method -> method.getReturnType().getName().equals("boolean"))
+ .forEach(method -> {
+ Update update = mock(Update.class);
+ try {
+ // Mock the method and make sure it returns true so that it gets processed by the following method
+ when(method.invoke(update)).thenReturn(true);
+ // Call the function, throws an IllegalStateException if there's an update that can't be processed
+ utilMethod.accept(update);
+ } catch (IllegalStateException e) {
+ throw new RuntimeException(
+ format("Found an update variation that is not handled by the getChatId util method [%s]", method.getName()), e);
+ } catch (NullPointerException | ReflectiveOperationException e) {
+ // This is fine, the mock isn't complete and we're only
+ // looking for IllegalStateExceptions thrown by the method
+ }
+ });
+ }
+
private void mockUser(Update update, Message message, User user) {
when(update.hasMessage()).thenReturn(true);
when(update.getMessage()).thenReturn(message);
diff --git a/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/bot/DefaultBot.java b/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/bot/DefaultBot.java
index 12db53f1..462453da 100644
--- a/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/bot/DefaultBot.java
+++ b/telegrambots-abilities/src/test/java/org/telegram/abilitybots/api/bot/DefaultBot.java
@@ -3,6 +3,7 @@ package org.telegram.abilitybots.api.bot;
import org.telegram.abilitybots.api.db.DBContext;
import org.telegram.abilitybots.api.objects.Ability;
import org.telegram.abilitybots.api.objects.Ability.AbilityBuilder;
+import org.telegram.abilitybots.api.objects.Reply;
import org.telegram.abilitybots.api.toggle.AbilityToggle;
import static org.telegram.abilitybots.api.objects.Ability.builder;
@@ -41,7 +42,7 @@ public class DefaultBot extends AbilityBot {
return getDefaultBuilder()
.name(DEFAULT)
.info("dis iz default command")
- .reply(upd -> silent.send("reply", upd.getMessage().getChatId()), MESSAGE, update -> update.getMessage().getText().equals("must reply"))
+ .reply(Reply.of(upd -> silent.send("reply", upd.getMessage().getChatId()), MESSAGE, update -> update.getMessage().getText().equals("must reply")).enableStats("mustreply"))
.reply(upd -> silent.send("reply", upd.getCallbackQuery().getMessage().getChatId()), CALLBACK_QUERY)
.build();
}
@@ -67,6 +68,7 @@ public class DefaultBot extends AbilityBot {
.privacy(PUBLIC)
.locality(USER)
.input(4)
+ .enableStats()
.build();
}
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 fb198278..bb5cd9e3 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
@@ -5,11 +5,13 @@ import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.telegram.abilitybots.api.db.DBContext;
+import org.telegram.abilitybots.api.objects.Flag;
import org.telegram.abilitybots.api.objects.Reply;
import org.telegram.abilitybots.api.objects.ReplyFlow;
import org.telegram.abilitybots.api.sender.MessageSender;
import org.telegram.abilitybots.api.sender.SilentSender;
import org.telegram.telegrambots.meta.api.objects.Update;
+import org.telegram.telegrambots.meta.api.objects.polls.Poll;
import java.io.IOException;
import java.util.function.Predicate;
@@ -106,6 +108,20 @@ public class ReplyFlowTest {
assertFalse(db.getMap(STATES).containsKey(chatId), "User still has state after terminal reply");
}
+ @Test
+ void repliesHandlePollResponse() {
+ Update update = mock(Update.class);
+ when(update.hasPoll()).thenReturn(true);
+ when(update.hasMessage()).thenReturn(false);
+
+ Poll poll = mock(Poll.class);
+ when(poll.getId()).thenReturn("1");
+ when(update.getPoll()).thenReturn(poll);
+
+ // This should not be processed as a reply, so we wouldn't filter out (true)
+ assertTrue(bot.filterReply(update));
+ }
+
public static class ReplyFlowBot extends AbilityBot {
private ReplyFlowBot(String botToken, String botUsername, DBContext db) {
@@ -139,7 +155,7 @@ public class ReplyFlowTest {
@NotNull
private Predicate hasMessageWith(String msg) {
- return upd -> upd.getMessage().getText().equalsIgnoreCase(msg);
+ return upd -> Flag.MESSAGE.test(upd) && upd.getMessage().getText().equalsIgnoreCase(msg);
}
}
}
diff --git a/telegrambots-chat-session-bot/README.md b/telegrambots-chat-session-bot/README.md
index 200dada6..4b80eb7d 100644
--- a/telegrambots-chat-session-bot/README.md
+++ b/telegrambots-chat-session-bot/README.md
@@ -15,7 +15,7 @@ Usage
org.telegram
telegrambots-chat-session-bot
- 4.8
+ 4.9
```
diff --git a/telegrambots-chat-session-bot/pom.xml b/telegrambots-chat-session-bot/pom.xml
index b2c39e4d..f93b46be 100644
--- a/telegrambots-chat-session-bot/pom.xml
+++ b/telegrambots-chat-session-bot/pom.xml
@@ -7,7 +7,7 @@
org.telegram
Bots
- 4.8
+ 4.9
telegrambots-chat-session-bot
@@ -84,7 +84,7 @@
org.telegram
telegrambots
- 4.8
+ 4.9
diff --git a/telegrambots-extensions/README.md b/telegrambots-extensions/README.md
index e1fdc519..247bb691 100644
--- a/telegrambots-extensions/README.md
+++ b/telegrambots-extensions/README.md
@@ -16,12 +16,12 @@ Just import add the library to your project with one of these options:
org.telegram
telegrambotsextensions
- 4.8
+ 4.9
```
2. Using Gradle:
```gradle
- compile "org.telegram:telegrambotsextensions:4.8"
+ compile "org.telegram:telegrambotsextensions:4.9"
```
\ No newline at end of file
diff --git a/telegrambots-extensions/pom.xml b/telegrambots-extensions/pom.xml
index f9c389ae..150d5c77 100644
--- a/telegrambots-extensions/pom.xml
+++ b/telegrambots-extensions/pom.xml
@@ -7,7 +7,7 @@
org.telegram
Bots
- 4.8
+ 4.9
telegrambotsextensions
@@ -75,7 +75,7 @@
org.telegram
telegrambots
- 4.8
+ 4.9
diff --git a/telegrambots-extensions/src/main/java/org/telegram/telegrambots/extensions/bots/commandbot/TelegramLongPollingCommandBot.java b/telegrambots-extensions/src/main/java/org/telegram/telegrambots/extensions/bots/commandbot/TelegramLongPollingCommandBot.java
index 1796b364..05de2c72 100644
--- a/telegrambots-extensions/src/main/java/org/telegram/telegrambots/extensions/bots/commandbot/TelegramLongPollingCommandBot.java
+++ b/telegrambots-extensions/src/main/java/org/telegram/telegrambots/extensions/bots/commandbot/TelegramLongPollingCommandBot.java
@@ -22,7 +22,6 @@ import java.util.function.BiConsumer;
*/
public abstract class TelegramLongPollingCommandBot extends TelegramLongPollingBot implements ICommandRegistry {
private final CommandRegistry commandRegistry;
- private String botUsername;
/**
* Creates a TelegramLongPollingCommandBot using default options
@@ -33,19 +32,6 @@ public abstract class TelegramLongPollingCommandBot extends TelegramLongPollingB
this(ApiContext.getInstance(DefaultBotOptions.class));
}
- /**
- * Creates a TelegramLongPollingCommandBot using default options
- * Use ICommandRegistry's methods on this bot to register commands
- *
- * @param botUsername Username of the bot
- * @deprecated Overwrite {@link #getBotUsername() getBotUsername} instead
- */
- @Deprecated
- public TelegramLongPollingCommandBot(String botUsername){
- this();
- this.botUsername = botUsername;
- }
-
/**
* Creates a TelegramLongPollingCommandBot with custom options and allowing commands with
* usernames
@@ -152,9 +138,7 @@ public abstract class TelegramLongPollingCommandBot extends TelegramLongPollingB
* @return Bot username
*/
@Override
- public String getBotUsername(){
- return this.botUsername;
- };
+ public abstract String getBotUsername();
/**
* Process all updates, that are not commands.
diff --git a/telegrambots-meta/pom.xml b/telegrambots-meta/pom.xml
index 240082ba..aa204715 100644
--- a/telegrambots-meta/pom.xml
+++ b/telegrambots-meta/pom.xml
@@ -7,7 +7,7 @@
org.telegram
Bots
- 4.8
+ 4.9
telegrambots-meta
diff --git a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/methods/send/SendDice.java b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/methods/send/SendDice.java
index 24d14cf8..a81c0fe4 100644
--- a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/methods/send/SendDice.java
+++ b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/methods/send/SendDice.java
@@ -10,14 +10,18 @@ import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
/**
* @author Ruben Bermudez
* @version 4.7
- * Use this method to send a dice, which will have a random value from 1 to 6. On success, the sent Message is returned.
- * (Yes, we're aware of the “proper” singular of die. But it's awkward, and we decided to help it change. One dice at a time!)
+ * Use this method to send an animated emoji that will display a random value. On success, the sent Message is returned.
*/
public class SendDice extends BotApiMethod {
+ private static final List VALIDEMOJIS = Collections.unmodifiableList(Arrays.asList("\uD83C\uDFB2", "\uD83C\uDFAF", "\uD83C\uDFC0"));
+
public static final String PATH = "sendDice";
private static final String CHATID_FIELD = "chat_id";
@@ -28,8 +32,12 @@ public class SendDice extends BotApiMethod {
@JsonProperty(CHATID_FIELD)
private String chatId; ///< Unique identifier for the target chat or username of the target channel (in the format @channelusername)
+ /**
+ * Emoji on which the dice throw animation is based. Currently, must be one of “🎲”, “🎯”, or “🏀”.
+ * Dice can have values 1-6 for “🎲” and “🎯”, and values 1-5 for “🏀”. Defauts to “🎲”
+ */
@JsonProperty(EMOJI_FIELD)
- private String emoji; ///< Optional. Emoji on which the dice throw animation is based. Currently, must be one of “🎲” or “🎯”. Defauts to “🎲”
+ private String emoji;
@JsonProperty(DISABLENOTIFICATION_FIELD)
private Boolean disableNotification; ///< Optional. Sends the message silently. Users will receive a notification with no sound.
@JsonProperty(REPLYTOMESSAGEID_FIELD)
@@ -121,8 +129,8 @@ public class SendDice extends BotApiMethod {
if (chatId == null) {
throw new TelegramApiValidationException("ChatId parameter can't be empty", this);
}
- if (emoji != null && !emoji.equals("“\uD83C\uDFB2") && !emoji.equals("\uD83C\uDFAF")) {
- throw new TelegramApiValidationException("Only \uD83C\uDFB2 and \uD83C\uDFAF are allowed in Emoji field ", this);
+ if (emoji != null && !VALIDEMOJIS.contains(emoji)) {
+ throw new TelegramApiValidationException("Only \uD83C\uDFB2, \uD83C\uDFAF or \uD83C\uDFC0 are allowed in Emoji field ", this);
}
if (replyMarkup != null) {
replyMarkup.validate();
diff --git a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/Dice.java b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/Dice.java
index 2b57eb80..b0983a63 100644
--- a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/Dice.java
+++ b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/Dice.java
@@ -6,15 +6,14 @@ import org.telegram.telegrambots.meta.api.interfaces.BotApiObject;
/**
* @author Ruben Bermudez
* @version 4.7
- * This object represents a dice with random value from 1 to 6.
- * (Yes, we're aware of the “proper” singular of die. But it's awkward, and we decided to help it change. One dice at a time!)
+ * This object represents an animated emoji that displays a random value.
*/
public class Dice implements BotApiObject {
private static final String VALUE_FIELD = "value";
private static final String EMOJI_FIELD = "emoji";
@JsonProperty(VALUE_FIELD)
- private Integer value; ///< Value of the dice, 1-6
+ private Integer value; ///< Value of the dice, 1-6 for “🎲” and “🎯” base emoji, 1-5 for “🏀” base emoji
@JsonProperty(EMOJI_FIELD)
private String emoji; ///< Emoji on which the dice throw animation is based
diff --git a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/Message.java b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/Message.java
index 551922ab..b0723615 100644
--- a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/Message.java
+++ b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/Message.java
@@ -68,6 +68,7 @@ public class Message implements BotApiObject {
private static final String POLL_FIELD = "poll";
private static final String REPLY_MARKUP_FIELD = "reply_markup";
private static final String DICE_FIELD = "dice";
+ private static final String VIABOT_FIELD = "via_bot";
@JsonProperty(MESSAGEID_FIELD)
private Integer messageId; ///< Integer Unique message identifier
@@ -210,7 +211,8 @@ public class Message implements BotApiObject {
private InlineKeyboardMarkup replyMarkup;
@JsonProperty(DICE_FIELD)
private Dice dice; // Optional. Message is a dice with random value from 1 to 6
-
+ @JsonProperty(VIABOT_FIELD)
+ private User viaBot; // Optional. Bot through which the message was sent
public Message() {
super();
}
@@ -521,6 +523,14 @@ public class Message implements BotApiObject {
return dice != null;
}
+ public User getViaBot() {
+ return viaBot;
+ }
+
+ public boolean hasViaBot() {
+ return viaBot != null;
+ }
+
public boolean hasReplyMarkup() {
return replyMarkup != null;
}
@@ -579,6 +589,8 @@ public class Message implements BotApiObject {
", forwardSenderName='" + forwardSenderName + '\'' +
", poll=" + poll +
", replyMarkup=" + replyMarkup +
+ ", dice=" + dice +
+ ", viaBot=" + viaBot +
'}';
}
}
diff --git a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/inlinequery/result/InlineQueryResultGif.java b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/inlinequery/result/InlineQueryResultGif.java
index b290ec8d..3a037830 100644
--- a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/inlinequery/result/InlineQueryResultGif.java
+++ b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/inlinequery/result/InlineQueryResultGif.java
@@ -7,6 +7,10 @@ import org.telegram.telegrambots.meta.api.objects.inlinequery.inputmessageconten
import org.telegram.telegrambots.meta.api.objects.replykeyboard.InlineKeyboardMarkup;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
/**
* @author Ruben Bermudez
* @version 1.0
@@ -16,12 +20,15 @@ import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
*/
@JsonDeserialize
public class InlineQueryResultGif implements InlineQueryResult {
+ private static final List VALIDTHUMBTYPES = Collections.unmodifiableList(Arrays.asList("image/jpeg", "image/gif", "video/mp4"));
+
private static final String TYPE_FIELD = "type";
private static final String ID_FIELD = "id";
private static final String GIFURL_FIELD = "gif_url";
private static final String GIFWIDTH_FIELD = "gif_width";
private static final String GIFHEIGHT_FIELD = "gif_height";
private static final String THUMBURL_FIELD = "thumb_url";
+ private static final String THUMBMIMETYPE_FIELD = "thumb_mime_type";
private static final String TITLE_FIELD = "title";
private static final String CAPTION_FIELD = "caption";
private static final String INPUTMESSAGECONTENT_FIELD = "input_message_content";
@@ -40,7 +47,9 @@ public class InlineQueryResultGif implements InlineQueryResult {
@JsonProperty(GIFHEIGHT_FIELD)
private Integer gifHeight; ///< Optional. Height of the GIF
@JsonProperty(THUMBURL_FIELD)
- private String thumbUrl; ///< Optional. URL of a static thumbnail for the result (jpeg or gif)
+ private String thumbUrl; ///< Optional. URL of the static (JPEG or GIF) or animated (MPEG4) thumbnail for the result
+ @JsonProperty(THUMBMIMETYPE_FIELD)
+ private String thumbUrlType; ///< Optional. MIME type of the thumbnail, must be one of “image/jpeg”, “image/gif”, or “video/mp4”
@JsonProperty(TITLE_FIELD)
private String title; ///< Optional. Title for the result
@JsonProperty(CAPTION_FIELD)
@@ -107,6 +116,15 @@ public class InlineQueryResultGif implements InlineQueryResult {
return this;
}
+ public String getThumbUrlType() {
+ return thumbUrlType;
+ }
+
+ public InlineQueryResultGif setThumbUrlType(String thumbUrlType) {
+ this.thumbUrlType = thumbUrlType;
+ return this;
+ }
+
public String getTitle() {
return title;
}
@@ -169,6 +187,9 @@ public class InlineQueryResultGif implements InlineQueryResult {
if (gifUrl == null || gifUrl.isEmpty()) {
throw new TelegramApiValidationException("GifUrl parameter can't be empty", this);
}
+ if (thumbUrlType != null && !VALIDTHUMBTYPES.contains(thumbUrlType)) {
+ throw new TelegramApiValidationException("ThumbUrlType parameter must be one of “image/jpeg”, “image/gif”, or “video/mp4”", this);
+ }
if (inputMessageContent != null) {
inputMessageContent.validate();
}
@@ -186,6 +207,7 @@ public class InlineQueryResultGif implements InlineQueryResult {
", gifWidth=" + gifWidth +
", gifHeight=" + gifHeight +
", thumbUrl='" + thumbUrl + '\'' +
+ ", thumbUrlType='" + thumbUrlType + '\'' +
", title='" + title + '\'' +
", caption='" + caption + '\'' +
", inputMessageContent=" + inputMessageContent +
diff --git a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/inlinequery/result/cached/InlineQueryResultCachedGif.java b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/inlinequery/result/cached/InlineQueryResultCachedGif.java
index 17661bb3..bee3d835 100644
--- a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/inlinequery/result/cached/InlineQueryResultCachedGif.java
+++ b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/inlinequery/result/cached/InlineQueryResultCachedGif.java
@@ -8,6 +8,10 @@ import org.telegram.telegrambots.meta.api.objects.inlinequery.result.InlineQuery
import org.telegram.telegrambots.meta.api.objects.replykeyboard.InlineKeyboardMarkup;
import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
/**
* @author Ruben Bermudez
* @version 1.0
@@ -17,11 +21,15 @@ import org.telegram.telegrambots.meta.exceptions.TelegramApiValidationException;
*/
@JsonDeserialize
public class InlineQueryResultCachedGif implements InlineQueryResult {
+ private static final List VALIDTHUMBTYPES = Collections.unmodifiableList(Arrays.asList("image/jpeg", "image/gif", "video/mp4"));
+
private static final String TYPE_FIELD = "type";
private static final String ID_FIELD = "id";
private static final String GIF_FILE_ID_FIELD = "gif_file_id";
private static final String TITLE_FIELD = "title";
private static final String CAPTION_FIELD = "caption";
+ private static final String THUMBURL_FIELD = "thumb_url";
+ private static final String THUMBMIMETYPE_FIELD = "thumb_mime_type";
private static final String INPUTMESSAGECONTENT_FIELD = "input_message_content";
private static final String REPLY_MARKUP_FIELD = "reply_markup";
private static final String PARSEMODE_FIELD = "parse_mode";
@@ -42,6 +50,10 @@ public class InlineQueryResultCachedGif implements InlineQueryResult {
private InlineKeyboardMarkup replyMarkup; ///< Optional. Inline keyboard attached to the message
@JsonProperty(PARSEMODE_FIELD)
private String parseMode; ///< Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in the media caption.
+ @JsonProperty(THUMBURL_FIELD)
+ private String thumbUrl; ///< Optional. URL of the static (JPEG or GIF) or animated (MPEG4) thumbnail for the result
+ @JsonProperty(THUMBMIMETYPE_FIELD)
+ private String thumbUrlType;
public InlineQueryResultCachedGif() {
super();
@@ -114,6 +126,24 @@ public class InlineQueryResultCachedGif implements InlineQueryResult {
return this;
}
+ public String getThumbUrl() {
+ return thumbUrl;
+ }
+
+ public InlineQueryResultCachedGif setThumbUrl(String thumbUrl) {
+ this.thumbUrl = thumbUrl;
+ return this;
+ }
+
+ public String getThumbUrlType() {
+ return thumbUrlType;
+ }
+
+ public InlineQueryResultCachedGif setThumbUrlType(String thumbUrlType) {
+ this.thumbUrlType = thumbUrlType;
+ return this;
+ }
+
@Override
public void validate() throws TelegramApiValidationException {
if (id == null || id.isEmpty()) {
@@ -122,6 +152,9 @@ public class InlineQueryResultCachedGif implements InlineQueryResult {
if (gifFileId == null || gifFileId.isEmpty()) {
throw new TelegramApiValidationException("GifFileId parameter can't be empty", this);
}
+ if (thumbUrlType != null && !VALIDTHUMBTYPES.contains(thumbUrlType)) {
+ throw new TelegramApiValidationException("ThumbUrlType parameter must be one of “image/jpeg”, “image/gif”, or “video/mp4”", this);
+ }
if (inputMessageContent != null) {
inputMessageContent.validate();
}
@@ -141,6 +174,8 @@ public class InlineQueryResultCachedGif implements InlineQueryResult {
", inputMessageContent=" + inputMessageContent +
", replyMarkup=" + replyMarkup +
", parseMode='" + parseMode + '\'' +
+ ", thumbUrl='" + thumbUrl + '\'' +
+ ", thumbUrlType='" + thumbUrlType + '\'' +
'}';
}
}
diff --git a/telegrambots-spring-boot-starter/pom.xml b/telegrambots-spring-boot-starter/pom.xml
index 30aa25f5..9e57f9f0 100644
--- a/telegrambots-spring-boot-starter/pom.xml
+++ b/telegrambots-spring-boot-starter/pom.xml
@@ -7,7 +7,7 @@
org.telegram
Bots
- 4.8
+ 4.9
telegrambots-spring-boot-starter
@@ -70,7 +70,8 @@
UTF-8
UTF-8
- 2.1.8.RELEASE
+
+ 2.2.2.RELEASE
@@ -78,7 +79,7 @@
org.telegram
telegrambots
- 4.8
+ 4.9
org.springframework.boot
diff --git a/telegrambots-spring-boot-starter/src/main/java/org/telegram/telegrambots/starter/TelegramBotInitializer.java b/telegrambots-spring-boot-starter/src/main/java/org/telegram/telegrambots/starter/TelegramBotInitializer.java
index c0911641..3c8168a6 100644
--- a/telegrambots-spring-boot-starter/src/main/java/org/telegram/telegrambots/starter/TelegramBotInitializer.java
+++ b/telegrambots-spring-boot-starter/src/main/java/org/telegram/telegrambots/starter/TelegramBotInitializer.java
@@ -4,7 +4,9 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.telegram.telegrambots.meta.TelegramBotsApi;
+import org.telegram.telegrambots.meta.api.objects.ApiResponse;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
+import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.generics.BotSession;
import org.telegram.telegrambots.meta.generics.LongPollingBot;
import org.telegram.telegrambots.meta.generics.WebhookBot;
@@ -55,6 +57,9 @@ public class TelegramBotInitializer implements InitializingBean {
private void handleAnnotatedMethod(Object bot, Method method, BotSession session) {
try {
+ TelegramApiRequestException test = new TelegramApiRequestException("Error getting updates", new ApiResponse());
+ log.error(test.getMessage(), test);
+
if (method.getParameterCount() > 1) {
log.warn(format("Method %s of Type %s has too many parameters",
method.getName(), method.getDeclaringClass().getCanonicalName()));
diff --git a/telegrambots-spring-boot-starter/src/main/java/org/telegram/telegrambots/starter/TelegramBotStarterConfiguration.java b/telegrambots-spring-boot-starter/src/main/java/org/telegram/telegrambots/starter/TelegramBotStarterConfiguration.java
index 5fe34191..6aea31d0 100644
--- a/telegrambots-spring-boot-starter/src/main/java/org/telegram/telegrambots/starter/TelegramBotStarterConfiguration.java
+++ b/telegrambots-spring-boot-starter/src/main/java/org/telegram/telegrambots/starter/TelegramBotStarterConfiguration.java
@@ -2,8 +2,9 @@ package org.telegram.telegrambots.starter;
import java.util.Collections;
import java.util.List;
-import java.util.Optional;
+
+import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
@@ -11,12 +12,11 @@ import org.springframework.context.annotation.Configuration;
import org.telegram.telegrambots.meta.TelegramBotsApi;
import org.telegram.telegrambots.meta.generics.LongPollingBot;
import org.telegram.telegrambots.meta.generics.WebhookBot;
-
/**
* #TelegramBotsApi added to spring context as well
*/
@Configuration
-@ConditionalOnProperty(prefix="telegrambots",name = "enabled", havingValue = "true", matchIfMissing = true)
+@ConditionalOnProperty(prefix = "telegrambots", name = "enabled", havingValue = "true", matchIfMissing = true)
public class TelegramBotStarterConfiguration {
@Bean
@@ -26,12 +26,12 @@ public class TelegramBotStarterConfiguration {
}
@Bean
- @ConditionalOnMissingBean
- public TelegramBotInitializer telegramBotInitializer(TelegramBotsApi telegramBotsApi,
- Optional> longPollingBots,
- Optional> webHookBots) {
- return new TelegramBotInitializer(telegramBotsApi,
- longPollingBots.orElseGet(Collections::emptyList),
- webHookBots.orElseGet(Collections::emptyList));
+ @ConditionalOnMissingBean
+ public TelegramBotInitializer telegramBotInitializer(TelegramBotsApi telegramBotsApi,
+ ObjectProvider> longPollingBots,
+ ObjectProvider> webHookBots) {
+ return new TelegramBotInitializer(telegramBotsApi,
+ longPollingBots.getIfAvailable(Collections::emptyList),
+ webHookBots.getIfAvailable(Collections::emptyList));
}
}
diff --git a/telegrambots/pom.xml b/telegrambots/pom.xml
index 01fa8538..48e1a0b2 100644
--- a/telegrambots/pom.xml
+++ b/telegrambots/pom.xml
@@ -7,7 +7,7 @@
org.telegram
Bots
- 4.8
+ 4.9
telegrambots
@@ -95,7 +95,7 @@
org.telegram
telegrambots-meta
- 4.8
+ 4.9
com.fasterxml.jackson.core
diff --git a/telegrambots/src/main/java/org/telegram/telegrambots/updatesreceivers/DefaultBotSession.java b/telegrambots/src/main/java/org/telegram/telegrambots/updatesreceivers/DefaultBotSession.java
index 0f9f6334..da98f1b8 100644
--- a/telegrambots/src/main/java/org/telegram/telegrambots/updatesreceivers/DefaultBotSession.java
+++ b/telegrambots/src/main/java/org/telegram/telegrambots/updatesreceivers/DefaultBotSession.java
@@ -26,6 +26,7 @@ import org.telegram.telegrambots.meta.generics.UpdatesReader;
import java.io.IOException;
import java.io.InvalidObjectException;
+import java.lang.reflect.InvocationTargetException;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.nio.charset.StandardCharsets;
@@ -274,7 +275,15 @@ public class DefaultBotSession implements BotSession {
} catch (InterruptedException e) {
log.info(e.getLocalizedMessage(), e);
interrupt();
+ } catch (InternalError e) {
+ // handle InternalError to workaround OpenJDK bug (resolved since 13.0)
+ // https://bugs.openjdk.java.net/browse/JDK-8173620
+ if (e.getCause() instanceof InvocationTargetException) {
+ Throwable cause = e.getCause().getCause();
+ log.error(cause.getLocalizedMessage(), cause);
+ } else throw e;
}
+
return Collections.emptyList();
}
}