Skip to content

Commit

Permalink
Add cold storage to bot, channel id is now persistent through restarts
Browse files Browse the repository at this point in the history
Improve performance client eviction check
Evict less often, but directly after disconnect, if required
Add method to grab HalfClients, fixes race conditions in InactivityTask
Fix max message size
  • Loading branch information
Kakifrucht committed Apr 13, 2017
1 parent 150d8d8 commit bcdfa24
Show file tree
Hide file tree
Showing 14 changed files with 167 additions and 65 deletions.
3 changes: 3 additions & 0 deletions README.md
Expand Up @@ -9,6 +9,9 @@ Current features
- Bot messages are fully configurable/localizable
- Automatic reconnect if connection is lost
- Define channel for bot to join, stays persistent if moved out
- Storage system
- Regulary stores client data to disk, if necessary
- Bot can be restarted without losing state, like the clients channel id
- Permission system
- Define what client belongs to which group via their talk power
- Higher groups automatically inherit all permissions of lower groups
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Expand Up @@ -7,7 +7,7 @@
<groupId>de.halfminer</groupId>
<artifactId>HalfminerBot</artifactId>
<name>Halfminer Bot</name>
<version>1.0.1</version>
<version>1.1</version>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
Expand Down
Expand Up @@ -9,7 +9,7 @@
/**
* Base inheritance class, keeping references to commonly used object instances.
*/
public class HalfminerBotClass {
public class BotClass {

protected final HalfminerBot bot = HalfminerBot.getInstance();
protected final YamlConfig config = bot.getConfig();
Expand Down
Expand Up @@ -2,10 +2,7 @@

import com.github.theholywaffle.teamspeak3.TS3Api;
import com.github.theholywaffle.teamspeak3.api.TextMessageTargetMode;
import com.github.theholywaffle.teamspeak3.api.event.ClientJoinEvent;
import com.github.theholywaffle.teamspeak3.api.event.ClientMovedEvent;
import com.github.theholywaffle.teamspeak3.api.event.TS3EventAdapter;
import com.github.theholywaffle.teamspeak3.api.event.TextMessageEvent;
import com.github.theholywaffle.teamspeak3.api.event.*;
import com.github.theholywaffle.teamspeak3.api.wrapper.ClientInfo;
import com.github.theholywaffle.teamspeak3.api.wrapper.ServerQueryInfo;
import de.halfminer.hmbot.cmd.CommandDispatcher;
Expand All @@ -18,9 +15,9 @@
/**
* Event listeners for bot. Passes commands to {@link CommandDispatcher} and contacts the client on server/channel join.
*/
class HalfminerBotListeners extends TS3EventAdapter {
class BotListeners extends TS3EventAdapter {

private final static Logger logger = LoggerFactory.getLogger(HalfminerBotListeners.class);
private final static Logger logger = LoggerFactory.getLogger(BotListeners.class);

private final HalfminerBot bot = HalfminerBot.getInstance();
private final YamlConfig config = bot.getConfig();
Expand All @@ -31,7 +28,7 @@ class HalfminerBotListeners extends TS3EventAdapter {
private final int idOfBot;
private final int channelOfBot;

HalfminerBotListeners() {
BotListeners() {
ServerQueryInfo info = api.whoAmI();
idOfBot = info.getId();
channelOfBot = info.getChannelId();
Expand All @@ -58,6 +55,11 @@ public void onClientJoin(ClientJoinEvent e) {
}
}

@Override
public void onClientLeave(ClientLeaveEvent e) {
storage.clientLeft(e.getClientId());
}

@Override
public void onClientMoved(ClientMovedEvent e) {

Expand All @@ -80,11 +82,14 @@ private boolean isRegularClient(int clientId) {
}

private void clientEnterMessageAndMove(int clientId) {
if (!storage.getClient(clientId).moveToChannel()) {
TS3Api api = bot.getApi();
clientEnterMessageAndMove(api.getClientInfo(clientId));
}

private void clientEnterMessageAndMove(ClientInfo client) {
if (!storage.getClient(client).moveToChannel()) {
MessageBuilder.create("joinMessage")
.addPlaceholderReplace("NICKNAME", api.getClientInfo(clientId).getNickname())
.sendMessage(clientId);
.addPlaceholderReplace("NICKNAME", client.getNickname())
.sendMessage(client.getId());
}
}
}
4 changes: 3 additions & 1 deletion src/main/java/de/halfminer/hmbot/HalfminerBot.java
Expand Up @@ -179,7 +179,7 @@ private boolean startBot() {
}

api.registerAllEvents();
api.addTS3Listeners(new HalfminerBotListeners());
api.addTS3Listeners(new BotListeners());
scheduler.registerAllTasks();

logger.info("HalfminerBot connected successfully and ready as {}", nickName);
Expand All @@ -203,7 +203,9 @@ public boolean reloadConfig() {
public void stop(String message, boolean restart) {

logger.info(message.length() > 0 ? message : "Bot quitting...");

if (scheduler != null) scheduler.shutdown();
if (storage != null) storage.doSaveOnDisk();
if (query != null) {
try {
query.exit();
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/de/halfminer/hmbot/cmd/CmdAdmin.java
Expand Up @@ -114,7 +114,7 @@ void run() throws InvalidCommandException {
}
}

StringBuilder send = new StringBuilder(nickName + ":\n");
StringBuilder send = new StringBuilder("======= ").append(nickName).append(" =======\n");
for (Map.Entry<String, String> entry : mapToSend.entrySet()) {
if (entry.getValue().length() == 0) continue;
send.append(" ").append(entry.getKey()).append("=").append(entry.getValue()).append("\n");
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/de/halfminer/hmbot/cmd/Command.java
@@ -1,7 +1,7 @@
package de.halfminer.hmbot.cmd;

import com.github.theholywaffle.teamspeak3.api.wrapper.ClientInfo;
import de.halfminer.hmbot.HalfminerBotClass;
import de.halfminer.hmbot.BotClass;
import de.halfminer.hmbot.storage.HalfClient;
import de.halfminer.hmbot.storage.Storage;
import de.halfminer.hmbot.util.MessageBuilder;
Expand All @@ -10,7 +10,7 @@
/**
* Command base class dispatched by {@link CommandDispatcher}.
*/
abstract class Command extends HalfminerBotClass {
abstract class Command extends BotClass {

final Storage storage = bot.getStorage();

Expand Down
4 changes: 2 additions & 2 deletions src/main/java/de/halfminer/hmbot/cmd/CommandDispatcher.java
Expand Up @@ -2,7 +2,7 @@

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import de.halfminer.hmbot.HalfminerBotClass;
import de.halfminer.hmbot.BotClass;
import de.halfminer.hmbot.storage.HalfClient;
import de.halfminer.hmbot.storage.Storage;
import de.halfminer.hmbot.util.MessageBuilder;
Expand All @@ -15,7 +15,7 @@
* Also does permission, flood and command limit checks, logs commands, sets default command
* and sends correct command usage, if invalid, to client.
*/
public class CommandDispatcher extends HalfminerBotClass {
public class CommandDispatcher extends BotClass {

private final Storage storage = bot.getStorage();
private final Cache<Integer, Boolean> floodProtection = CacheBuilder.newBuilder()
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/de/halfminer/hmbot/cmd/CommandEnum.java
Expand Up @@ -10,7 +10,7 @@
/**
* Access to {@link Command command's} class name and their usage and description key for messaging.
*/
public enum CommandEnum {
enum CommandEnum {

ADMIN (CmdAdmin.class),
BROADCAST (CmdBroadcast.class),
Expand Down
38 changes: 25 additions & 13 deletions src/main/java/de/halfminer/hmbot/storage/HalfClient.java
@@ -1,29 +1,32 @@
package de.halfminer.hmbot.storage;

import com.github.theholywaffle.teamspeak3.api.wrapper.Channel;
import com.github.theholywaffle.teamspeak3.api.wrapper.Client;
import com.github.theholywaffle.teamspeak3.api.wrapper.ClientInfo;
import de.halfminer.hmbot.HalfminerBotClass;
import de.halfminer.hmbot.BotClass;
import de.halfminer.hmbot.util.MessageBuilder;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
* Client class managed by {@link Storage}.
*/
public class HalfClient extends HalfminerBotClass {
public class HalfClient extends BotClass {

private int clientId;
private HalfGroup group;

private boolean isOnline;
private final Map<Class, Long> commandCooldown = new ConcurrentHashMap<>();

private int channelId = Integer.MIN_VALUE;

HalfClient(int clientId, HalfGroup group) {
this.clientId = clientId;
this.group = group;
updateClient(clientId, group);
}

int getClientId() {
return clientId;
}

public ClientInfo getClientInfo() {
Expand All @@ -46,22 +49,32 @@ public void addCooldown(Class commandClass, int cooldownSeconds) {
commandCooldown.put(commandClass, (System.currentTimeMillis() / 1000) + cooldownSeconds);
}

boolean canBeEvicted(List<Client> clients) {
boolean isOnline = clients.stream()
.map(Client::getId)
.anyMatch(id -> id == clientId);
return !isOnline && getChannel() == null && clearCommandCooldown();
boolean doSaveToDisk() {
return getChannel() != null;
}

boolean isOnline() {
return isOnline;
}

void updateClient(int clientId, HalfGroup group) {
this.clientId = clientId;
this.group = group;
this.isOnline = true;
}

void setOffline() {
isOnline = false;
}

public void setChannelId(int channelId) {
this.channelId = channelId;
}

int getChannelId() {
return channelId;
}

public Channel getChannel() {

if (channelId > Integer.MIN_VALUE) {
Expand Down Expand Up @@ -98,10 +111,9 @@ public boolean moveToChannel() {
return false;
}

private boolean clearCommandCooldown() {
private void clearCommandCooldown() {
long currentTime = System.currentTimeMillis() / 1000;
commandCooldown.values().removeIf(timeStamp -> timeStamp < currentTime);
return commandCooldown.size() == 0;
}

@Override
Expand Down

0 comments on commit bcdfa24

Please sign in to comment.