diff --git a/.classpath b/.classpath index 91ec221..e147ff5 100644 --- a/.classpath +++ b/.classpath @@ -1,9 +1,14 @@ - - - - + + + + + + + + + diff --git a/src/pkg/deepCurse/nopalmo/command/GuildCommand.java b/src/pkg/deepCurse/nopalmo/command/GuildCommand.java new file mode 100644 index 0000000..81ec544 --- /dev/null +++ b/src/pkg/deepCurse/nopalmo/command/GuildCommand.java @@ -0,0 +1,41 @@ +package pkg.deepCurse.nopalmo.command; + +import net.dv8tion.jda.api.Permission; +import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; +import pkg.deepCurse.nopalmo.manager.CommandBlob; +import pkg.deepCurse.nopalmo.manager.GuildCommandManager; + +public abstract class GuildCommand { + + public abstract void run(CommandBlob blob, GuildMessageReceivedEvent guildMessage, GuildCommandManager commandManager) throws Exception; + + public abstract String[] getCommandCalls(); + + public String getCommandName() { + return getCommandCalls()[0]; + } + + public boolean isHidden() { + return false; + } + + public boolean isNSFW() { + return false; + } + + public Permission[] getRequiredPermissions() { + return null; + } + + public boolean isPremium() { // im probably never gonna use this, but ill leave it in for those who want to + // see how i would implement it + return false; + } + + public abstract HelpPage getHelpPage(); + + public enum HelpPage { + General, DEV, EGG, Moderation, Fun, Info + } + +} diff --git a/src/pkg/deepCurse/nopalmo/command/guildCommand/Ping.java b/src/pkg/deepCurse/nopalmo/command/guildCommand/Ping.java new file mode 100644 index 0000000..79c0b80 --- /dev/null +++ b/src/pkg/deepCurse/nopalmo/command/guildCommand/Ping.java @@ -0,0 +1,28 @@ +package pkg.deepCurse.nopalmo.command.guildCommand; + +import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; +import pkg.deepCurse.nopalmo.command.GuildCommand; +import pkg.deepCurse.nopalmo.database.DatabaseTools; +import pkg.deepCurse.nopalmo.manager.CommandBlob; +import pkg.deepCurse.nopalmo.manager.GuildCommandManager; + +public class Ping extends GuildCommand { + + @Override + public void run(CommandBlob blob, GuildMessageReceivedEvent guildMessage, GuildCommandManager commandManager) + throws Exception { + + DatabaseTools.Tools.Guild.Prefix.createPrefix(guildMessage.getGuild().getIdLong(), blob.getArgs().get(0)); + + } + + @Override + public String[] getCommandCalls() { + return new String[] {"ping"}; + } + + @Override + public HelpPage getHelpPage() { + return HelpPage.Info; + } +} diff --git a/src/pkg/deepCurse/nopalmo/core/Boot.java b/src/pkg/deepCurse/nopalmo/core/Boot.java index eec22c8..293580e 100644 --- a/src/pkg/deepCurse/nopalmo/core/Boot.java +++ b/src/pkg/deepCurse/nopalmo/core/Boot.java @@ -1,18 +1,66 @@ package pkg.deepCurse.nopalmo.core; +import java.sql.SQLException; + +import javax.security.auth.login.LoginException; + +import net.dv8tion.jda.api.JDA; +import net.dv8tion.jda.api.JDABuilder; +import net.dv8tion.jda.api.entities.Activity; +import net.dv8tion.jda.api.requests.GatewayIntent; +import net.dv8tion.jda.api.utils.ChunkingFilter; +import net.dv8tion.jda.api.utils.MemberCachePolicy; +import pkg.deepCurse.nopalmo.database.DatabaseTools; +import pkg.deepCurse.nopalmo.global.Reactions; +import pkg.deepCurse.nopalmo.listener.GuildMessageReceivedListener; +import pkg.deepCurse.nopalmo.manager.GuildCommandManager; import pkg.deepCurse.simpleLoggingGarbage.core.Log; public class Boot { + public static JDA bot; + public static DatabaseTools databaseTools = null; + public static GuildCommandManager guildCommandManager = new GuildCommandManager(); // move to master manager + public static boolean isProd = false; + public static void main(String[] args) { Log.boot("Booting. . ."); long preBootTime = System.currentTimeMillis(); + isProd = args[2].contentEquals("prod"); + Log.boot("Connecting to mariadb:nopalmo"); + try { + databaseTools = new DatabaseTools(args[1]); + Log.boot("Connected. . ."); + } catch (SQLException e1) { + e1.printStackTrace(); + Log.boot("Failed to connect. . .\nShutting down. . ."); + System.exit(4); + } + Log.boot("Init reaction/emote list"); + Reactions.init(); + Log.boot("Initialized reaction/emote list. . ."); + Log.boot("Init commands list"); + guildCommandManager.init(); + Log.boot("Initialized commands list. . ."); + + try { + bot = JDABuilder.createDefault(args[0]).setChunkingFilter(ChunkingFilter.NONE) + .setMemberCachePolicy(MemberCachePolicy.NONE).enableIntents(GatewayIntent.GUILD_MEMBERS) + .setActivity(Activity.watching("Loading users...")).setIdle(true) + .addEventListeners(new GuildMessageReceivedListener()).build().awaitReady(); + } catch (LoginException e) { + Log.crash(e); + } catch (InterruptedException e) { + e.printStackTrace(); + } + long bootTime = System.currentTimeMillis() - preBootTime; - + + System.out.println("Taken "+bootTime+"ms to boot"); + } - } diff --git a/src/pkg/deepCurse/nopalmo/database/DatabaseTools.java b/src/pkg/deepCurse/nopalmo/database/DatabaseTools.java new file mode 100644 index 0000000..3dd18f3 --- /dev/null +++ b/src/pkg/deepCurse/nopalmo/database/DatabaseTools.java @@ -0,0 +1,325 @@ +package pkg.deepCurse.nopalmo.database; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import javax.annotation.Nonnull; + +import org.jetbrains.annotations.Nullable; + +import pkg.deepCurse.nopalmo.core.Boot; +import pkg.deepCurse.nopalmo.database.DatabaseTools.Tools.Global; +import pkg.deepCurse.simpleLoggingGarbage.core.Log; + +public class DatabaseTools { + + private static Connection connection = null; + + public DatabaseTools(String password) throws SQLException { + connection = createConnection(password); + Global.updatePrefix(); + } + + public static Connection createConnection(String password) throws SQLException { + + String dbName = Boot.isProd ? "nopalmo" : "chaos"; + + String driver = "com.mysql.cj.jdbc.Driver"; + String url = "jdbc:mysql://localhost/" + dbName; + String username = "nopalmo"; + try { + Class.forName(driver); + } catch (ClassNotFoundException e) { + Log.crash(e); + } + + try { + return DriverManager.getConnection(url, username, password); + } catch (SQLException e) { + sqlTranslate("Generate connection", e); + throw new SQLException(e); + } + } + + private static void sqlTranslate(String action, int errorCode) { + switch (errorCode) { + case 1062: + System.err.println("Failed to execute; errorCode=" + errorCode + "; ER_DUP_ENTRY; On action " + action); + break; + case 1054: + System.err.println("Failed to execute; errorCode=" + errorCode + "; ER_BAD_FIELD_ERROR; On action " + action); + break; + default: + System.err.println("Failed to execute; errorCode=" + errorCode + "; Unknown code; On action " + action); + break; + } + } + + @Deprecated + private static void sqlTranslate(String action, SQLException e) { + sqlTranslate(action, e.getErrorCode()); + } + + private static void sqlTranslate(PreparedStatement pstmt, SQLException e) { + sqlTranslate(pstmt.toString(), e.getErrorCode()); + } + + private static void checkUpdateCounts(PreparedStatement pstmt, int[] updateCounts) { + checkUpdateCounts(pstmt.toString(), updateCounts); + } + + @Deprecated + public static void checkUpdateCounts(String action, int[] updateCounts) { + for (int i = 0; i < updateCounts.length; i++) { + if (updateCounts[i] >= 0) { + System.out.println("Successfully executed; updateCount=" + updateCounts[i] + "; On action " + action); + } else if (updateCounts[i] == Statement.SUCCESS_NO_INFO) { + System.out.println("Successfully executed; updateCount=Statement.SUCCESS_NO_INFO; On action " + action); + } else if (updateCounts[i] == Statement.EXECUTE_FAILED) { + System.out.println("Failed to execute; updateCount=Statement.EXECUTE_FAILED; On action " + action); + } + } + } + + public class Tools { + + // these sub classes will represent tables and the methods therein will be for actions within said table + + public class Guild { + + public class Prefix { + + @Nullable + public static String getPrefix(@Nonnull long guildID) { + Statement st = null; + ResultSet rs = null; + String query = "select * from guilds where guildid = " + guildID; + try { + st = connection.createStatement(); + rs = st.executeQuery(query); + if (rs.next()) { + return rs.getString("prefix"); + } else { + // throw new SQLException(null, null, 33); // we need a real catcher here + System.err.println( + "Failed to execute; errorCode=NO_ROW_FOUND; No row found; On action " + query); + return createPrefix(guildID, Global.prefix); + } + } catch (SQLException e) { + sqlTranslate(query, e.getErrorCode()); + return null; + } finally { // @formatter:off + try {if (rs != null)rs.close();} catch (Exception e) {} + try {if (st != null)st.close();} catch (Exception e) {} + // @formatter:on + } + } + + public static String createPrefix(@Nonnull long guildID, @Nullable String prefix) + throws IllegalArgumentException { + + if (prefix == null || prefix.isEmpty()) { + // throw new IllegalArgumentException("Input cannot be empty"); + prefix = ";"; + } + + PreparedStatement pstmt = null; + + String query = "insert into guilds(guildid, prefix) values(?, ?);"; + try { + pstmt = connection.prepareStatement(query); + + pstmt.setLong(1, guildID); + pstmt.setString(2, prefix); + pstmt.addBatch(); + + int[] updateCounts = pstmt.executeBatch(); + checkUpdateCounts(pstmt, updateCounts); + pstmt.close(); + // connection.commit(); + return prefix; + } catch (SQLException e) { + sqlTranslate(pstmt, e); + for (int i : new int[] { 1062 }) { + if (i == e.getErrorCode()) { + return setPrefix(connection, guildID, prefix); + } + } + try { + connection.rollback(); + } catch (Exception e2) { + e.printStackTrace(); + } + return null; + } + } + + public static String setPrefix(Connection conn, long guildID, String prefix) + throws IllegalArgumentException { + + if (prefix.isEmpty()) { + throw new IllegalArgumentException("Input cannot be empty"); + } + + PreparedStatement pstmt = null; + + String query = "update guilds set prefix = ? where guildid = ?;"; + try { + pstmt = conn.prepareStatement(query); + + pstmt.setLong(2, guildID); + pstmt.setString(1, prefix); + pstmt.addBatch(); + + int[] updateCounts = pstmt.executeBatch(); + checkUpdateCounts(pstmt, updateCounts); + pstmt.close(); + conn.commit(); + return prefix; + } catch (SQLException e) { + sqlTranslate(pstmt, e); + try { + conn.rollback(); + } catch (Exception e2) { + e.printStackTrace(); + } + return null; + } + } + } + } + + public class Developers { + + public static boolean canPowerOffBot(long userID) { + Statement st = null; + ResultSet rs = null; + String query = "select * from developers where userid = " + userID; + try { + st = connection.createStatement(); + rs = st.executeQuery(query); + if (rs.next()) { + return rs.getBoolean("canpoweroffbot"); + } else { + // throw new SQLException(null, null, 33); // we need a real catcher here + System.err + .println("Failed to execute; errorCode=NO_ROW_FOUND; No row found; On action " + query); + return false; + } + + } catch (SQLException e) { + sqlTranslate(query, e.getErrorCode()); + // System.out.println("eeeeee"); + return false; + } finally { + try { + if (rs != null) + rs.close(); + } catch (Exception e) { + } + + try { + if (st != null) + st.close(); + } catch (Exception e) { + } + + // try { if (conn != null) conn.close(); } catch (Exception e) {}; + } + // return null; + } + + } + + public class Global { + + public static String prefix = null; + + public static void updatePrefix() throws SQLException { + Statement st = null; + ResultSet rs = null; + String query = "select * from global where id = 'prefix'"; + String msg = "Failed to execute; errorCode=NO_ROW_FOUND; No row found; On action " + query; + try { + st = connection.createStatement(); + rs = st.executeQuery(query); + if (rs.next()) { + prefix = rs.getString("value"); + } else { + // throw new SQLException(null, null, 33); // we need a real catcher here + + System.err.println(msg); + throw new NullPointerException(msg); + } + + } catch (SQLException e) { + sqlTranslate(query, e.getErrorCode()); + // System.out.println("eeeeee"); + throw new SQLException(e); + } finally { + try { + if (rs != null) + rs.close(); + } catch (Exception e) { + } + + try { + if (st != null) + st.close(); + } catch (Exception e) { + } + + // try { if (conn != null) conn.close(); } catch (Exception e) {}; + } + // return null; + } + + } + +// public class Reaction { // started off as a good idea but it sucks +// public static String getReaction(long reactionID) { +// Statement st = null; +// ResultSet rs = null; +// String query = "select * from reactions where id = '"+reactionID+"'"; +// try { +// st = connection.createStatement(); +// rs = st.executeQuery(query); +// if (rs.next()) { +// return rs.getString("val"); +// } else { +// // throw new SQLException(null, null, 33); // we need a real catcher here +// System.err +// .println("Failed to execute; errorCode=NO_ROW_FOUND; No row found; On action " + query); +// return null; +// } +// +// } catch (SQLException e) { +// sqlTranslate(query, e.getErrorCode()); +// // System.out.println("eeeeee"); +// return null; +// } finally { +// try { +// if (rs != null) +// rs.close(); +// } catch (Exception e) { +// } +// +// try { +// if (st != null) +// st.close(); +// } catch (Exception e) { +// } +// +// // try { if (conn != null) conn.close(); } catch (Exception e) {}; +// } +// // return null; +// } +// } + + } + +} diff --git a/src/pkg/deepCurse/nopalmo/global/Reactions.java b/src/pkg/deepCurse/nopalmo/global/Reactions.java new file mode 100644 index 0000000..002a4aa --- /dev/null +++ b/src/pkg/deepCurse/nopalmo/global/Reactions.java @@ -0,0 +1,25 @@ +package pkg.deepCurse.nopalmo.global; + +import java.util.HashMap; + +public class Reactions { + + private static HashMap reactionMap = new HashMap(); + + public static void init() { + insert("galaxyThumb", 801657838358495232L); + } + + public static void insert(String input, long id) { + reactionMap.put(input, id); + } + + public static String getReaction(String id) { + return ":"+id+":"+reactionMap.get(id); + } + + public static String getEmote(String id) { + return "<:"+id+":"+reactionMap.get(id)+">"; + } + +} diff --git a/src/pkg/deepCurse/nopalmo/global/Tools.java b/src/pkg/deepCurse/nopalmo/global/Tools.java new file mode 100644 index 0000000..68ec254 --- /dev/null +++ b/src/pkg/deepCurse/nopalmo/global/Tools.java @@ -0,0 +1,5 @@ +package pkg.deepCurse.nopalmo.global; + +public class Tools { + +} diff --git a/src/pkg/deepCurse/nopalmo/listener/GuildMessageReceivedListener.java b/src/pkg/deepCurse/nopalmo/listener/GuildMessageReceivedListener.java new file mode 100644 index 0000000..731197b --- /dev/null +++ b/src/pkg/deepCurse/nopalmo/listener/GuildMessageReceivedListener.java @@ -0,0 +1,62 @@ +package pkg.deepCurse.nopalmo.listener; + +import javax.annotation.Nonnull; + +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.events.ReadyEvent; +import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; +import pkg.deepCurse.nopalmo.core.Boot; +import pkg.deepCurse.nopalmo.database.DatabaseTools; +import pkg.deepCurse.nopalmo.database.DatabaseTools.Tools.Global; +import pkg.deepCurse.nopalmo.global.Reactions; +import pkg.deepCurse.nopalmo.manager.GuildCommandManager; + +public class GuildMessageReceivedListener extends ListenerAdapter { + + @Override + public void onReady(@Nonnull ReadyEvent event) { + System.out.println("GuildMessageReceivedListener is now ready\n" + event.getGuildAvailableCount() + "/" + + event.getGuildTotalCount() + " : " + event.getGuildUnavailableCount() + " <" + + event.getResponseNumber() + ">"); + } + + @Override + public void onGuildMessageReceived(@Nonnull GuildMessageReceivedEvent event) { + Message message = event.getMessage(); + String messageRaw = message.getContentRaw(); + String[] prefixArray = new String[] { DatabaseTools.Tools.Guild.Prefix.getPrefix(event.getGuild().getIdLong()), + "<@!" + event.getJDA().getSelfUser().getIdLong() + ">" }; + + boolean shouldReturn = true; + for (String i : prefixArray) { + if (messageRaw.startsWith(i)) { + shouldReturn = false; + } + } + + if (messageRaw.contentEquals(Global.prefix + Global.prefix) + && DatabaseTools.Tools.Developers.canPowerOffBot(event.getAuthor().getIdLong())) { + message.addReaction(Reactions.getReaction("galaxyThumb")).complete(); + + System.out.println("Shutting down; id " + event.getAuthor().getIdLong() + " used"); + + // pause thread as last resort + + event.getJDA().shutdown(); + System.exit(0); + } + + // TODO add pre manager commands + + if (shouldReturn) { + return; + } + + if (!event.getAuthor().isBot()) { + Boot.guildCommandManager.startCommand(event); + } + + } + +} diff --git a/src/pkg/deepCurse/nopalmo/manager/CommandBlob.java b/src/pkg/deepCurse/nopalmo/manager/CommandBlob.java new file mode 100644 index 0000000..05752ed --- /dev/null +++ b/src/pkg/deepCurse/nopalmo/manager/CommandBlob.java @@ -0,0 +1,24 @@ +package pkg.deepCurse.nopalmo.manager; + +import java.util.ArrayList; + +public class CommandBlob { + + private String modifiedRaw = null; + private String modified = null; + + private ArrayList args = null; + + public String getModifiedMessageContents() { + return this.modified; + } + + public String getModifiedRawMessageContents() { + return this.modifiedRaw; + } + + public ArrayList getArgs() { + return args; + } + +} diff --git a/src/pkg/deepCurse/nopalmo/manager/GuildCommandManager.java b/src/pkg/deepCurse/nopalmo/manager/GuildCommandManager.java new file mode 100644 index 0000000..c8e9cb2 --- /dev/null +++ b/src/pkg/deepCurse/nopalmo/manager/GuildCommandManager.java @@ -0,0 +1,99 @@ +package pkg.deepCurse.nopalmo.manager; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.regex.Pattern; + +import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; +import pkg.deepCurse.nopalmo.command.GuildCommand; +import pkg.deepCurse.nopalmo.command.guildCommand.Ping; +import pkg.deepCurse.nopalmo.core.Boot; +import pkg.deepCurse.nopalmo.database.DatabaseTools; + +public class GuildCommandManager { + + private final Map guildCommandMap = new HashMap<>(); + Executor executor = null; + + public GuildCommandManager() { + init(); + executor = Executors.newSingleThreadExecutor(); + } + + public void init() { + addCommand(new Ping()); + } + + private void addCommand(GuildCommand c) { + if (!guildCommandMap.containsKey(c.getCommandName())) { + guildCommandMap.put(c.getCommandName(), c); + } else { + guildCommandMap.remove(c.getCommandName()); + guildCommandMap.put(c.getCommandName(), c); + } + } + + public Collection getguildCommandMap() { + return guildCommandMap.values(); + } + + public GuildCommand getCommand(String commandName) { + if (commandName != null) { + return guildCommandMap.get(commandName); + } + return null; + } + + public void startCommand(GuildMessageReceivedEvent guildMessage) { + + final String message = guildMessage.getMessage().getContentRaw(); + + final String[] split = message.replaceFirst("(?i)" + Pattern.quote(DatabaseTools.Tools.Global.prefix), "") + .split("\\s+"); + final String command = split[0].toLowerCase(); + + executor.execute(() -> { + long commandStartTime = System.currentTimeMillis(); + + try { + + ArrayList newArguments = new ArrayList(); + + ArrayList extractedFlags = new ArrayList(); + + } catch (Exception e) { + if (Boot.isProd) { + guildMessage.getChannel().sendMessage("```\n" + e + "```").queue(); + } else { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + e.printStackTrace(pw); + guildMessage.getChannel().sendMessage("```\n" + sw.toString() + "```").queue(); + System.err.println("Exception caught in: " + e.toString()); + e.printStackTrace(); + } + } catch (Throwable t) { + + if (Boot.isProd) { + guildMessage.getChannel().sendMessage("```\n" + t + "```").queue(); + } else { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + t.printStackTrace(pw); + guildMessage.getChannel().sendMessage("```\n" + sw.toString() + "```").queue(); + System.err.println("Error caught in: " + t.toString()); + t.printStackTrace(); + } + + } + + }); + } + +} diff --git a/src/pkg/deepCurse/simpleLoggingGarbage/core/Log.java b/src/pkg/deepCurse/simpleLoggingGarbage/core/Log.java index e64f46c..f7224d0 100644 --- a/src/pkg/deepCurse/simpleLoggingGarbage/core/Log.java +++ b/src/pkg/deepCurse/simpleLoggingGarbage/core/Log.java @@ -1,5 +1,7 @@ package pkg.deepCurse.simpleLoggingGarbage.core; +import javax.security.auth.login.LoginException; + /** * this class exists for the sole reason of im lazy, as far as i know, this is * really bad practice and i will replace it at some point, or at least upgrade @@ -22,4 +24,6 @@ public class Log { } } //@formatter:on + public static void crash(Exception e) { + } }