0

Added basic bot functionality

This commit is contained in:
David Panić
2019-07-17 00:34:21 +02:00
parent 73e632044a
commit 2bd7a69e7e
15 changed files with 866 additions and 40 deletions

View File

@@ -0,0 +1,13 @@
package com.redstoner.redstonerBot;
public class Env {
public static final String TOKEN = System.getenv("TOKEN");
public static final String MYSQL_HOST = System.getenv("MYSQL_HOST");
public static final String MYSQL_PORT = System.getenv("MYSQL_PORT");
public static final String MYSQL_USER = System.getenv("MYSQL_USER");
public static final String MYSQL_PASS = System.getenv("MYSQL_PASS");
public static final String MYSQL_DB = System.getenv("MYSQL_DB");
}

View File

@@ -1,12 +1,62 @@
package com.redstoner.redstonerBot;
import com.redstoner.redstonerBot.managers.CommandManager;
import com.redstoner.redstonerBot.managers.DataManager;
import com.redstoner.redstonerBot.managers.DiscordManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Main {
public static final Logger logger = LoggerFactory.getLogger(Main.class);
private static final Logger logger = LoggerFactory.getLogger(Main.class);
private static final List<Manager> managers = new ArrayList<>();
private static final List<Manager> loadedManagers = new ArrayList<>();
static {
managers.add(new DataManager());
managers.add(new DiscordManager());
managers.add(new CommandManager());
}
public static void main(final String... args) {
logger.info("Starting RedstonerBot...");
if (!start()) {
stop();
System.exit(1);
}
}
private static boolean start() {
loadedManagers.clear();
for (Manager m : managers) {
if (m.start()) {
loadedManagers.add(m);
} else {
return false;
}
}
return true;
}
public static boolean stop() {
for (Manager m : getReversedManagers()) {
if (!m.stop()) return false;
}
return true;
}
private static List<Manager> getReversedManagers() {
List<Manager> reversedManagers = new ArrayList<>(loadedManagers);
Collections.reverse(reversedManagers);
return reversedManagers;
}
}

View File

@@ -0,0 +1,6 @@
package com.redstoner.redstonerBot;
public interface Manager {
boolean start();
boolean stop();
}

View File

@@ -0,0 +1,7 @@
package com.redstoner.redstonerBot.commands;
import net.dv8tion.jda.core.entities.*;
public interface Command {
boolean execute(Guild guild, TextChannel channel, Message message, User author, Member self, String command, String[] params);
}

View File

@@ -0,0 +1,24 @@
package com.redstoner.redstonerBot.commands;
import com.redstoner.redstonerBot.managers.DiscordManager;
import net.dv8tion.jda.core.EmbedBuilder;
import net.dv8tion.jda.core.entities.*;
import java.awt.*;
public class InfoCommand implements Command {
@Override
public boolean execute(Guild guild, TextChannel channel, Message message, User author, Member self, String command, String[] params) {
EmbedBuilder embed = new EmbedBuilder();
embed.setTitle("Information");
embed.setDescription("This is a Discord bot built by psrcek for the Redstoner Guild.");
embed.setColor(Color.ORANGE);
embed.setFooter("Redstoner bot", "https://cdn.discordapp.com/avatars/576432236702859284/b08d4dc368b2e041ebb3fc208a2e8230.png");
message.getChannel().sendMessage(embed.build()).queue(DiscordManager::expireMessage);
return true;
}
}

View File

@@ -0,0 +1,25 @@
package com.redstoner.redstonerBot.commands;
import com.redstoner.redstonerBot.Main;
import com.redstoner.redstonerBot.managers.DiscordManager;
import net.dv8tion.jda.core.entities.*;
public class StopCommand implements Command {
@Override
public boolean execute(Guild guild, TextChannel channel, Message message, User author, Member self, String command, String[] params) {
if (!guild.getOwnerId().equals(author.getId())) return false;
message.getChannel().sendMessage("This bot will stop in 5 seconds, as requested by " + author.getAsTag()).queue(DiscordManager::expireMessage);
new Thread(() -> {
try {
Thread.sleep(6000);
} catch (InterruptedException ignored) {
}
Main.stop();
}).start();
return true;
}
}

View File

@@ -0,0 +1,43 @@
package com.redstoner.redstonerBot.listeners;
import com.redstoner.redstonerBot.managers.CommandManager;
import com.redstoner.redstonerBot.managers.DataManager;
import net.dv8tion.jda.core.Permission;
import net.dv8tion.jda.core.entities.*;
import net.dv8tion.jda.core.events.message.guild.GuildMessageReceivedEvent;
import net.dv8tion.jda.core.hooks.ListenerAdapter;
import net.dv8tion.jda.core.utils.Checks;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Objects;
public class MessageReceived extends ListenerAdapter {
private static final Logger logger = LoggerFactory.getLogger(MessageReceived.class);
@Override
public final void onGuildMessageReceived(GuildMessageReceivedEvent event) {
Checks.notNull(event, "Event");
final Guild guild = event.getGuild();
final TextChannel channel = event.getChannel();
final Message message = event.getMessage();
final User author = event.getAuthor();
final Member self = guild.getSelfMember();
if (!Objects.equals(guild.getId(), DataManager.getConfigValue("guild_id"))) return;
if (author.isBot()) return;
if (message.isTTS()) return;
if (!self.hasPermission(channel, Permission.MESSAGE_WRITE)) return;
if (!self.hasPermission(channel, Permission.MESSAGE_EMBED_LINKS)) return;
String rawMessage = message.getContentRaw();
logger.info(author.getAsTag() + " -> " + rawMessage);
if (rawMessage.startsWith(DataManager.getConfigValue("prefix_char"))) {
CommandManager.execute(guild, channel, message, author, self);
}
}
}

View File

@@ -0,0 +1,61 @@
package com.redstoner.redstonerBot.managers;
import com.redstoner.redstonerBot.Manager;
import com.redstoner.redstonerBot.commands.Command;
import com.redstoner.redstonerBot.commands.InfoCommand;
import com.redstoner.redstonerBot.commands.StopCommand;
import net.dv8tion.jda.core.entities.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
public class CommandManager implements Manager {
private static final Logger logger = LoggerFactory.getLogger(CommandManager.class);
private static Map<String, Command> commands = new HashMap<>();
@Override
public boolean start() {
logger.info("Command Manager starting...");
commands.put("info", new InfoCommand());
commands.put("stop", new StopCommand());
logger.info("Command Manager started!");
return true;
}
@Override
public boolean stop() {
logger.info("Command Manager stopping...");
commands.clear();
logger.info("Command Manager stopped!");
return true;
}
public static void execute(Guild guild, TextChannel channel, Message message, User author, Member self) {
String rawMsg = message.getContentRaw();
String[] rawCmd = rawMsg.split(" ");
String cmd = rawCmd[0].substring(1);
String[] params = Arrays.copyOfRange(rawCmd, 1, rawCmd.length);
Command command = commands.get(cmd);
if (command == null) return;
logger.info("[" + message.getId() + "] User '" + author.getAsTag() + "' executed command " + cmd + " with parameters " + Arrays.toString(params));
if (command.execute(guild, channel, message, author, self, cmd, params)) {
logger.info("[" + message.getId() + "] Command executed successfully!");
} else {
logger.error("[" + message.getId() + "] Error while executing command!");
}
message.delete().reason("Redstoner Bot command execution").queue();
}
}

View File

@@ -0,0 +1,118 @@
package com.redstoner.redstonerBot.managers;
import com.redstoner.redstonerBot.Env;
import com.redstoner.redstonerBot.Manager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class DataManager implements Manager {
private static final Logger logger = LoggerFactory.getLogger(DataManager.class);
private static final String[] requiredTables = { "config", "opt_in", "rules", "rule_agree_reactions" };
private static Map<String, String> config = new HashMap<>();
public boolean start() {
logger.info("Data Manager starting...");
if (checkConnection()) {
logger.info("Loading config...");
if (!loadConfig()) {
logger.error("Data Manager failed to load config!");
return false;
}
logger.info("Data Manager started!");
return true;
} else {
logger.error("Data Manager failed to start!");
return false;
}
}
public boolean stop() {
logger.info("Data Manager stopping...");
config.clear();
logger.info("Data Manager stopped!");
return true;
}
private static String getConnectionString() {
return "jdbc:mysql://"
+ Env.MYSQL_HOST + ":" + Env.MYSQL_PORT
+ "/" + Env.MYSQL_DB
+ "?useUnicode=true&characterEncoding=UTF-8"
+ "&user=" + Env.MYSQL_USER
+ "&password=" + Env.MYSQL_PASS;
}
private static Connection getConnection() throws SQLException {
return DriverManager.getConnection(getConnectionString());
}
private boolean checkConnection() {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection conn = getConnection();
ResultSet rs = conn.prepareStatement("show tables").executeQuery();
List<String> tables = new ArrayList<>();
while (rs.next()) {
tables.add(rs.getString(1));
}
conn.close();
for (String rt : requiredTables) {
if (!tables.contains(rt)) {
logger.error("The " + rt + " table is missing from the database!");
return false;
}
}
return true;
} catch (ClassNotFoundException | SQLException e) {
logger.error("SQL error:", e);
return false;
}
}
public static String getConfigValue(String name) {
return config.get(name);
}
public boolean loadConfig() {
config.clear();
try {
Connection conn = getConnection();
ResultSet rs = conn.prepareStatement("SELECT * FROM config").executeQuery();
while (rs.next()) {
String name = rs.getString(2);
String value = rs.getString(3);
config.put(name, value);
}
return true;
} catch (SQLException e) {
logger.error("SQL error:", e);
return false;
}
}
}

View File

@@ -0,0 +1,69 @@
package com.redstoner.redstonerBot.managers;
import com.redstoner.redstonerBot.Env;
import com.redstoner.redstonerBot.Manager;
import com.redstoner.redstonerBot.listeners.MessageReceived;
import net.dv8tion.jda.core.AccountType;
import net.dv8tion.jda.core.JDA;
import net.dv8tion.jda.core.JDABuilder;
import net.dv8tion.jda.core.entities.Guild;
import net.dv8tion.jda.core.entities.Message;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.security.auth.login.LoginException;
import java.util.concurrent.TimeUnit;
public class DiscordManager implements Manager {
private static final Logger logger = LoggerFactory.getLogger(DiscordManager.class);
private JDA jda;
public boolean start() {
logger.info("Discord Manager starting...");
try {
final JDABuilder builder = new JDABuilder(AccountType.BOT);
builder.setAutoReconnect(true);
builder.setAudioEnabled(true);
builder.setToken(Env.TOKEN);
builder.addEventListener(new MessageReceived());
jda = builder.build().awaitReady();
} catch (LoginException e) {
logger.error("The discord token is invalid!");
return false;
} catch (Throwable t) {
logger.error("JDA setup error:", t);
return false;
}
Guild guild = jda.getGuildById(DataManager.getConfigValue("guild_id"));
String guildName = guild.getName();
String infoChannelName = guild.getTextChannelById(DataManager.getConfigValue("info_channel_id")).getName();
logger.info("Discord Manager started and logged in as '" + jda.getSelfUser().getName() + "'");
logger.info("Listening to guild '" + guildName + "'");
logger.info("Using channel '" + infoChannelName + "' as the info channel");
logger.info("Discord Manager started!");
return true;
}
public boolean stop() {
logger.info("Discord Manager stopping...");
jda.shutdown();
logger.info("Discord Manager stopped!");
return true;
}
public static void expireMessage(Message message) {
message.delete().reason("Redstoner Bot message expiry").queueAfter(5, TimeUnit.SECONDS);
}
}