Merge pull request #812 from christianblos/feature/lazy-load-abilities

Feature/lazy load abilities
This commit is contained in:
Ruben Bermudez 2020-10-23 00:25:46 +01:00 committed by GitHub
commit aa030fa148
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 166 additions and 140 deletions

View File

@ -64,4 +64,15 @@ protected boolean allowContinuousText() {
Please note that this may cause ability overlap. If multiple abilities can match the same command, the longest match will be taken. For example, Please note that this may cause ability overlap. If multiple abilities can match the same command, the longest match will be taken. For example,
if you have two abilities `do` and `do1`, the command `/do1` will trigger the `do1` ability. if you have two abilities `do` and `do1`, the command `/do1` will trigger the `do1` ability.
## Statistics ## Statistics
AbilityBot can accrue basic statistics about the usage of your abilities and replies. Simply `enableStats()` on an Ability builder or `enableStats(<name>)` on replies to activate this feature. Once activated, you may call `/stats` and the bot will print a basic list of statistics. At the moment, AbilityBot only tracks hits. In the future, this will be enhanced to track more stats. AbilityBot can accrue basic statistics about the usage of your abilities and replies. Simply `enableStats()` on an Ability builder or `enableStats(<name>)` on replies to activate this feature. Once activated, you may call `/stats` and the bot will print a basic list of statistics. At the moment, AbilityBot only tracks hits. In the future, this will be enhanced to track more stats.
## Execute code on bot registration
If you want to execute custom logic to initialize your bot, but you can't do it in the constructor,
you can override the `onRegister()` method:
```
@Override
public void onRegister() {
super.onRegister();
// Execute custom initialize logic here
}
```

View File

@ -104,6 +104,8 @@ public class ExampleBotTest {
public void setUp() { public void setUp() {
// Create your bot // Create your bot
bot = new ExampleBot(); bot = new ExampleBot();
// Call onRegister() to initialize abilities etc.
bot.onRegister();
// Create a new sender as a mock // Create a new sender as a mock
silent = mock(SilentSender.class); silent = mock(SilentSender.class);
// Set your bot silent sender to the mocked sender // Set your bot silent sender to the mocked sender
@ -156,6 +158,7 @@ public class ExampleBotTest {
// Offline instance will get deleted at JVM shutdown // Offline instance will get deleted at JVM shutdown
db = MapDBContext.offlineInstance("test"); db = MapDBContext.offlineInstance("test");
bot = new ExampleBot(db); bot = new ExampleBot(db);
bot.onRegister();
... ...
} }
@ -180,6 +183,7 @@ public class ExampleBotTest {
@Before @Before
public void setUp() { public void setUp() {
bot = new ExampleBot(db); bot = new ExampleBot(db);
bot.onRegister();
sender = mock(MessageSender.class); sender = mock(MessageSender.class);
SilentSender silent = new SilentSender(sender); SilentSender silent = new SilentSender(sender);
// Create setter in your bot // Create setter in your bot

View File

@ -18,45 +18,45 @@ import static org.telegram.abilitybots.api.db.MapDBContext.onlineInstance;
* @author Abbas Abou Daya * @author Abbas Abou Daya
*/ */
public abstract class AbilityBot extends BaseAbilityBot implements LongPollingBot { public abstract class AbilityBot extends BaseAbilityBot implements LongPollingBot {
protected AbilityBot(String botToken, String botUsername, DBContext db, AbilityToggle toggle, DefaultBotOptions botOptions) { protected AbilityBot(String botToken, String botUsername, DBContext db, AbilityToggle toggle, DefaultBotOptions botOptions) {
super(botToken, botUsername, db, toggle, botOptions); super(botToken, botUsername, db, toggle, botOptions);
} }
protected AbilityBot(String botToken, String botUsername, AbilityToggle toggle, DefaultBotOptions options) { protected AbilityBot(String botToken, String botUsername, AbilityToggle toggle, DefaultBotOptions options) {
this(botToken, botUsername, onlineInstance(botUsername), toggle, options); this(botToken, botUsername, onlineInstance(botUsername), toggle, options);
} }
protected AbilityBot(String botToken, String botUsername, DBContext db, AbilityToggle toggle) { protected AbilityBot(String botToken, String botUsername, DBContext db, AbilityToggle toggle) {
this(botToken, botUsername, db, toggle, new DefaultBotOptions()); this(botToken, botUsername, db, toggle, new DefaultBotOptions());
} }
protected AbilityBot(String botToken, String botUsername, DBContext db, DefaultBotOptions options) { protected AbilityBot(String botToken, String botUsername, DBContext db, DefaultBotOptions options) {
this(botToken, botUsername, db, new DefaultToggle(), options); this(botToken, botUsername, db, new DefaultToggle(), options);
} }
protected AbilityBot(String botToken, String botUsername, DefaultBotOptions botOptions) { protected AbilityBot(String botToken, String botUsername, DefaultBotOptions botOptions) {
this(botToken, botUsername, onlineInstance(botUsername), botOptions); this(botToken, botUsername, onlineInstance(botUsername), botOptions);
} }
protected AbilityBot(String botToken, String botUsername, AbilityToggle toggle) { protected AbilityBot(String botToken, String botUsername, AbilityToggle toggle) {
this(botToken, botUsername, onlineInstance(botUsername), toggle); this(botToken, botUsername, onlineInstance(botUsername), toggle);
} }
protected AbilityBot(String botToken, String botUsername, DBContext db) { protected AbilityBot(String botToken, String botUsername, DBContext db) {
this(botToken, botUsername, db, new DefaultToggle()); this(botToken, botUsername, db, new DefaultToggle());
} }
protected AbilityBot(String botToken, String botUsername) { protected AbilityBot(String botToken, String botUsername) {
this(botToken, botUsername, onlineInstance(botUsername)); this(botToken, botUsername, onlineInstance(botUsername));
} }
@Override @Override
public void onUpdateReceived(Update update) { public void onUpdateReceived(Update update) {
super.onUpdateReceived(update); super.onUpdateReceived(update);
} }
@Override @Override
public void clearWebhook() throws TelegramApiRequestException { public void clearWebhook() throws TelegramApiRequestException {
WebhookUtils.clearWebhook(this); WebhookUtils.clearWebhook(this);
} }
} }

View File

@ -21,54 +21,54 @@ import static org.telegram.abilitybots.api.db.MapDBContext.onlineInstance;
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
public abstract class AbilityWebhookBot extends BaseAbilityBot implements WebhookBot { public abstract class AbilityWebhookBot extends BaseAbilityBot implements WebhookBot {
private final String botPath; private final String botPath;
protected AbilityWebhookBot(String botToken, String botUsername, String botPath, DBContext db, AbilityToggle toggle, DefaultBotOptions botOptions) { protected AbilityWebhookBot(String botToken, String botUsername, String botPath, DBContext db, AbilityToggle toggle, DefaultBotOptions botOptions) {
super(botToken, botUsername, db, toggle, botOptions); super(botToken, botUsername, db, toggle, botOptions);
this.botPath = botPath; this.botPath = botPath;
} }
protected AbilityWebhookBot(String botToken, String botUsername, String botPath, AbilityToggle toggle, DefaultBotOptions options) { protected AbilityWebhookBot(String botToken, String botUsername, String botPath, AbilityToggle toggle, DefaultBotOptions options) {
this(botToken, botUsername, botPath, onlineInstance(botUsername), toggle, options); this(botToken, botUsername, botPath, onlineInstance(botUsername), toggle, options);
} }
protected AbilityWebhookBot(String botToken, String botUsername, String botPath, DBContext db, AbilityToggle toggle) { protected AbilityWebhookBot(String botToken, String botUsername, String botPath, DBContext db, AbilityToggle toggle) {
this(botToken, botUsername, botPath, db, toggle, new DefaultBotOptions()); this(botToken, botUsername, botPath, db, toggle, new DefaultBotOptions());
} }
protected AbilityWebhookBot(String botToken, String botUsername, String botPath, DBContext db, DefaultBotOptions options) { protected AbilityWebhookBot(String botToken, String botUsername, String botPath, DBContext db, DefaultBotOptions options) {
this(botToken, botUsername, botPath, db, new DefaultToggle(), options); this(botToken, botUsername, botPath, db, new DefaultToggle(), options);
} }
protected AbilityWebhookBot(String botToken, String botUsername, String botPath, DefaultBotOptions botOptions) { protected AbilityWebhookBot(String botToken, String botUsername, String botPath, DefaultBotOptions botOptions) {
this(botToken, botUsername, botPath, onlineInstance(botUsername), botOptions); this(botToken, botUsername, botPath, onlineInstance(botUsername), botOptions);
} }
protected AbilityWebhookBot(String botToken, String botUsername, String botPath, AbilityToggle toggle) { protected AbilityWebhookBot(String botToken, String botUsername, String botPath, AbilityToggle toggle) {
this(botToken, botUsername, botPath, onlineInstance(botUsername), toggle); this(botToken, botUsername, botPath, onlineInstance(botUsername), toggle);
} }
protected AbilityWebhookBot(String botToken, String botUsername, String botPath, DBContext db) { protected AbilityWebhookBot(String botToken, String botUsername, String botPath, DBContext db) {
this(botToken, botUsername, botPath, db, new DefaultToggle()); this(botToken, botUsername, botPath, db, new DefaultToggle());
} }
protected AbilityWebhookBot(String botToken, String botUsername, String botPath) { protected AbilityWebhookBot(String botToken, String botUsername, String botPath) {
this(botToken, botUsername, botPath, onlineInstance(botUsername)); this(botToken, botUsername, botPath, onlineInstance(botUsername));
} }
@Override @Override
public BotApiMethod onWebhookUpdateReceived(Update update) { public BotApiMethod onWebhookUpdateReceived(Update update) {
super.onUpdateReceived(update); super.onUpdateReceived(update);
return null; return null;
} }
@Override @Override
public void setWebhook(String url, String publicCertificatePath) throws TelegramApiRequestException { public void setWebhook(String url, String publicCertificatePath) throws TelegramApiRequestException {
WebhookUtils.setWebhook(this, url, publicCertificatePath); WebhookUtils.setWebhook(this, url, publicCertificatePath);
} }
@Override @Override
public String getBotPath() { public String getBotPath() {
return botPath; return botPath;
} }
} }

View File

@ -123,7 +123,9 @@ public abstract class BaseAbilityBot extends DefaultAbsSender implements Ability
this.toggle = toggle; this.toggle = toggle;
this.sender = new DefaultSender(this); this.sender = new DefaultSender(this);
silent = new SilentSender(sender); silent = new SilentSender(sender);
}
public void onRegister() {
registerAbilities(); registerAbilities();
initStats(); initStats();
} }

View File

@ -33,6 +33,7 @@ class AbilityBotI18nTest {
void setUp() { void setUp() {
db = offlineInstance("db"); db = offlineInstance("db");
bot = new NoPublicCommandsBot(EMPTY, EMPTY, db); bot = new NoPublicCommandsBot(EMPTY, EMPTY, db);
bot.onRegister();
defaultAbs = new DefaultAbilities(bot); defaultAbs = new DefaultAbilities(bot);
sender = mock(MessageSender.class); sender = mock(MessageSender.class);

View File

@ -71,6 +71,7 @@ public class AbilityBotTest {
void setUp() { void setUp() {
db = offlineInstance("db"); db = offlineInstance("db");
bot = new DefaultBot(EMPTY, EMPTY, db); bot = new DefaultBot(EMPTY, EMPTY, db);
bot.onRegister();
defaultAbs = new DefaultAbilities(bot); defaultAbs = new DefaultAbilities(bot);
sender = mock(MessageSender.class); sender = mock(MessageSender.class);

View File

@ -33,6 +33,7 @@ public class ContinuousTextTest {
void setUp() { void setUp() {
db = offlineInstance("db"); db = offlineInstance("db");
bot = new ContinuousTextBot(EMPTY, EMPTY, db); bot = new ContinuousTextBot(EMPTY, EMPTY, db);
bot.onRegister();
silent = mock(SilentSender.class); silent = mock(SilentSender.class);
bot.silent = silent; bot.silent = silent;
} }

View File

@ -19,6 +19,7 @@ class ExtensionTest {
@BeforeEach @BeforeEach
void setUp() { void setUp() {
bot = new ExtensionUsingBot(); bot = new ExtensionUsingBot();
bot.onRegister();
} }
@AfterEach @AfterEach

View File

@ -39,6 +39,7 @@ public class ReplyFlowTest {
void setUp() { void setUp() {
db = offlineInstance("db"); db = offlineInstance("db");
bot = new ReplyFlowBot(EMPTY, EMPTY, db); bot = new ReplyFlowBot(EMPTY, EMPTY, db);
bot.onRegister();
sender = mock(MessageSender.class); sender = mock(MessageSender.class);
silent = mock(SilentSender.class); silent = mock(SilentSender.class);

View File

@ -26,6 +26,7 @@ public class BareboneToggleTest {
db = offlineInstance("db"); db = offlineInstance("db");
toggle = new BareboneToggle(); toggle = new BareboneToggle();
bareboneBot = new DefaultBot(EMPTY, EMPTY, db, toggle); bareboneBot = new DefaultBot(EMPTY, EMPTY, db, toggle);
bareboneBot.onRegister();
defaultAbs = new DefaultAbilities(bareboneBot); defaultAbs = new DefaultAbilities(bareboneBot);
} }

View File

@ -1,7 +1,6 @@
package org.telegram.abilitybots.api.toggle; package org.telegram.abilitybots.api.toggle;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.telegram.abilitybots.api.bot.DefaultAbilities; import org.telegram.abilitybots.api.bot.DefaultAbilities;
@ -18,12 +17,10 @@ class CustomToggleTest {
private DBContext db; private DBContext db;
private AbilityToggle toggle; private AbilityToggle toggle;
private DefaultBot customBot; private DefaultBot customBot;
private DefaultAbilities defaultAbs;
@BeforeEach @BeforeEach
void setUp() { void setUp() {
db = offlineInstance("db"); db = offlineInstance("db");
defaultAbs = new DefaultAbilities(customBot);
} }
@AfterEach @AfterEach
@ -36,6 +33,7 @@ class CustomToggleTest {
public void canTurnOffAbilities() { public void canTurnOffAbilities() {
toggle = new CustomToggle().turnOff(DefaultAbilities.CLAIM); toggle = new CustomToggle().turnOff(DefaultAbilities.CLAIM);
customBot = new DefaultBot(EMPTY, EMPTY, db, toggle); customBot = new DefaultBot(EMPTY, EMPTY, db, toggle);
customBot.onRegister();
assertFalse(customBot.abilities().containsKey(DefaultAbilities.CLAIM)); assertFalse(customBot.abilities().containsKey(DefaultAbilities.CLAIM));
} }
@ -44,6 +42,7 @@ class CustomToggleTest {
String targetName = DefaultAbilities.CLAIM + "1toggle"; String targetName = DefaultAbilities.CLAIM + "1toggle";
toggle = new CustomToggle().toggle(DefaultAbilities.CLAIM, targetName); toggle = new CustomToggle().toggle(DefaultAbilities.CLAIM, targetName);
customBot = new DefaultBot(EMPTY, EMPTY, db, toggle); customBot = new DefaultBot(EMPTY, EMPTY, db, toggle);
customBot.onRegister();
assertTrue(customBot.abilities().containsKey(targetName)); assertTrue(customBot.abilities().containsKey(targetName));
} }

View File

@ -3,7 +3,6 @@ package org.telegram.abilitybots.api.toggle;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.telegram.abilitybots.api.bot.DefaultAbilities;
import org.telegram.abilitybots.api.bot.DefaultBot; import org.telegram.abilitybots.api.bot.DefaultBot;
import org.telegram.abilitybots.api.db.DBContext; import org.telegram.abilitybots.api.db.DBContext;
import org.telegram.abilitybots.api.objects.Ability; import org.telegram.abilitybots.api.objects.Ability;
@ -18,52 +17,53 @@ import static org.telegram.abilitybots.api.bot.DefaultAbilities.*;
import static org.telegram.abilitybots.api.db.MapDBContext.offlineInstance; import static org.telegram.abilitybots.api.db.MapDBContext.offlineInstance;
class DefaultToggleTest { class DefaultToggleTest {
private DBContext db; private DBContext db;
private AbilityToggle toggle; private AbilityToggle toggle;
private DefaultBot defaultBot; private DefaultBot defaultBot;
private DefaultAbilities defaultAbs;
@BeforeEach @BeforeEach
void setUp() { void setUp() {
db = offlineInstance("db"); db = offlineInstance("db");
defaultAbs = new DefaultAbilities(defaultBot); }
}
@AfterEach @AfterEach
void tearDown() throws IOException { void tearDown() throws IOException {
db.clear(); db.clear();
db.close(); db.close();
} }
@Test @Test
public void claimsEveryAbilityIsOn() { public void claimsEveryAbilityIsOn() {
Ability random = DefaultBot.getDefaultBuilder() Ability random = DefaultBot.getDefaultBuilder()
.name("randomsomethingrandom").build(); .name("randomsomethingrandom").build();
toggle = new DefaultToggle(); toggle = new DefaultToggle();
defaultBot = new DefaultBot(EMPTY, EMPTY, db, toggle); defaultBot = new DefaultBot(EMPTY, EMPTY, db, toggle);
defaultBot.onRegister();
assertFalse(toggle.isOff(random)); assertFalse(toggle.isOff(random));
} }
@Test @Test
public void passedSameAbilityRefOnProcess() { public void passedSameAbilityRefOnProcess() {
Ability random = DefaultBot.getDefaultBuilder() Ability random = DefaultBot.getDefaultBuilder()
.name("randomsomethingrandom").build(); .name("randomsomethingrandom").build();
toggle = new DefaultToggle(); toggle = new DefaultToggle();
defaultBot = new DefaultBot(EMPTY, EMPTY, db, toggle); defaultBot = new DefaultBot(EMPTY, EMPTY, db, toggle);
defaultBot.onRegister();
assertSame(random, toggle.processAbility(random), "Toggle returned a different ability"); assertSame(random, toggle.processAbility(random), "Toggle returned a different ability");
} }
@Test @Test
public void allAbilitiesAreRegistered() { public void allAbilitiesAreRegistered() {
toggle = new DefaultToggle(); toggle = new DefaultToggle();
defaultBot = new DefaultBot(EMPTY, EMPTY, db, toggle); defaultBot = new DefaultBot(EMPTY, EMPTY, db, toggle);
Set<String> defaultNames = newHashSet( defaultBot.onRegister();
CLAIM, BAN, UNBAN, Set<String> defaultNames = newHashSet(
PROMOTE, DEMOTE, RECOVER, CLAIM, BAN, UNBAN,
BACKUP, REPORT, COMMANDS); PROMOTE, DEMOTE, RECOVER,
BACKUP, REPORT, COMMANDS);
assertTrue(defaultBot.abilities().keySet().containsAll(defaultNames), "Toggle returned a different ability"); assertTrue(defaultBot.abilities().keySet().containsAll(defaultNames), "Toggle returned a different ability");
} }
} }

View File

@ -117,6 +117,7 @@ public class TelegramBotsApi {
* @param bot the bot to register * @param bot the bot to register
*/ */
public BotSession registerBot(LongPollingBot bot) throws TelegramApiRequestException { public BotSession registerBot(LongPollingBot bot) throws TelegramApiRequestException {
bot.onRegister();
bot.clearWebhook(); bot.clearWebhook();
BotSession session = ApiContext.getInstance(BotSession.class); BotSession session = ApiContext.getInstance(BotSession.class);
session.setToken(bot.getBotToken()); session.setToken(bot.getBotToken());
@ -132,6 +133,7 @@ public class TelegramBotsApi {
*/ */
public void registerBot(WebhookBot bot) throws TelegramApiRequestException { public void registerBot(WebhookBot bot) throws TelegramApiRequestException {
if (useWebhook) { if (useWebhook) {
bot.onRegister();
webhook.registerWebhook(bot); webhook.registerWebhook(bot);
bot.setWebhook(externalUrl + bot.getBotPath(), pathToCertificate); bot.setWebhook(externalUrl + bot.getBotPath(), pathToCertificate);
} }

View File

@ -11,7 +11,7 @@ import java.util.List;
* @brief Callback to handle updates. * @brief Callback to handle updates.
* @date 20 of June of 2015 * @date 20 of June of 2015
*/ */
public interface LongPollingBot { public interface LongPollingBot extends TelegramBot {
/** /**
* This method is called when receiving updates via GetUpdates method * This method is called when receiving updates via GetUpdates method
* @param update Update received * @param update Update received
@ -27,16 +27,6 @@ public interface LongPollingBot {
updates.forEach(this::onUpdateReceived); updates.forEach(this::onUpdateReceived);
} }
/**
* Return bot username of this bot
*/
String getBotUsername();
/**
* Return bot token to access Telegram API
*/
String getBotToken();
/** /**
* Gets options for current bot * Gets options for current bot
* @return BotOptions object with options information * @return BotOptions object with options information

View File

@ -0,0 +1,24 @@
package org.telegram.telegrambots.meta.generics;
/**
* Main interface for telegram bots.
*/
public interface TelegramBot {
/**
* Return username of this bot
*/
String getBotUsername();
/**
* Return bot token to access Telegram API
*/
String getBotToken();
/**
* Is called when bot gets registered
*/
default void onRegister() {
}
}

View File

@ -10,25 +10,13 @@ import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
* @brief Callback to handle updates. * @brief Callback to handle updates.
* @date 20 of June of 2015 * @date 20 of June of 2015
*/ */
public interface WebhookBot { public interface WebhookBot extends TelegramBot {
/** /**
* This method is called when receiving updates via webhook * This method is called when receiving updates via webhook
* @param update Update received * @param update Update received
*/ */
BotApiMethod onWebhookUpdateReceived(Update update); BotApiMethod onWebhookUpdateReceived(Update update);
/**
* Gets bot username of this bot
* @return Bot username
*/
String getBotUsername();
/**
* Gets bot token to access Telegram API
* @return Bot token
*/
String getBotToken();
/** /**
* Execute setWebhook method to set up the url of the webhook * Execute setWebhook method to set up the url of the webhook
* @param url Url for the webhook * @param url Url for the webhook