diff --git a/src/main/java/netneutrality/ThreadManager.java b/src/main/java/netneutrality/ThreadManager.java index 614c5e0..4a4239c 100644 --- a/src/main/java/netneutrality/ThreadManager.java +++ b/src/main/java/netneutrality/ThreadManager.java @@ -18,19 +18,19 @@ public class ThreadManager { public static void shutdownExecutor() { try { - System.out.println("[Executor] Shutting down..."); + MusicBot.LOGGER.info("[Executor] Shutting down..."); executor.shutdown(); executor.awaitTermination(5, TimeUnit.SECONDS); } catch (InterruptedException e) { - System.err.println("[Executor] Running tasks interrupted"); + MusicBot.LOGGER.warn("[Executor] Running tasks interrupted"); } finally { if (!executor.isTerminated()) { - System.err.println("[Executor] Forcing shutdown of running tasks.."); + MusicBot.LOGGER.warn("[Executor] Forcing shutdown of running tasks.."); } executor.shutdownNow(); - System.out.println("[Executor] Shutdown finished!"); + MusicBot.LOGGER.info("[Executor] Shutdown finished!"); } } } diff --git a/src/main/java/netneutrality/command/message/BlacklistCommand.java b/src/main/java/netneutrality/command/message/BlacklistCommand.java index ce71bc6..e54836c 100644 --- a/src/main/java/netneutrality/command/message/BlacklistCommand.java +++ b/src/main/java/netneutrality/command/message/BlacklistCommand.java @@ -48,7 +48,7 @@ public class BlacklistCommand extends AbstractCommand { switch (parseArgs(args, 0)) { case "get": - event.getTextChannel().sendMessage("Retreiving list, please wait...").queue(t -> { + event.getTextChannel().sendMessage("Retrieving list, please wait...").queue(t -> { try { diff --git a/src/main/java/netneutrality/db/AsyncMySqlAction.java b/src/main/java/netneutrality/db/AsyncMySqlAction.java new file mode 100644 index 0000000..fab9ce2 --- /dev/null +++ b/src/main/java/netneutrality/db/AsyncMySqlAction.java @@ -0,0 +1,87 @@ +package netneutrality.db; + +/* + * Copyright (c) anthorob + * + * https://xtremcommunity.com/ + * https://discord.gg/CdFcyQ + */ + +import netneutrality.MusicBot; +import netneutrality.ThreadManager; +import netneutrality.db.models.MTableModel; + +import java.sql.ResultSet; +import java.util.function.Consumer; + +public class AsyncMySqlAction { + + private String sqlString; + private Object[] params; + private MysqlDatabase.CommandType type; + private MysqlDatabase db; + + public AsyncMySqlAction(MysqlDatabase db, String sql, Object... params) { + this.db = db; + this.sqlString = sql; + this.params = params; + + type = MysqlDatabase.CommandType.stringToType(sqlString.toUpperCase().split(" ")[0]); + } + + + public void async(Consumer success) { + switch (type) { + case INSERT: + ThreadManager.executor.submit(() -> { + db.insert(this.sqlString, this.params); + }); + break; + case UPDATE: + ThreadManager.executor.submit(() -> { + db.update(this.sqlString, this.params); + }); + break; + + case DELETE: + ThreadManager.executor.submit(() -> { + db.delete(this.sqlString, this.params); + }); + break; + + case SELECT: + ThreadManager.executor.submit(() -> { + ResultSet result = db.prepareAndExecute(this.sqlString, this.params); + MTableModel table = MysqlDatabase.convertToTableModel(result); + + success.accept(table); + }); + break; + } + } + + public void async() { + async(o -> { + }); + } + + public MTableModel blocking() { + switch (type) { + case INSERT: + db.insert(this.sqlString, this.params); + + case UPDATE: + db.update(this.sqlString, this.params); + + case DELETE: + db.delete(this.sqlString, this.params); + + case SELECT: + ResultSet result = db.prepareAndExecute(this.sqlString, this.params); + + return MysqlDatabase.convertToTableModel(result); + } + + return null; + } +} diff --git a/src/main/java/netneutrality/db/DBController.java b/src/main/java/netneutrality/db/DBController.java index 1d96ddd..ef37578 100644 --- a/src/main/java/netneutrality/db/DBController.java +++ b/src/main/java/netneutrality/db/DBController.java @@ -13,7 +13,7 @@ import org.reflections.Reflections; /** * When creating a controller, all database actions must be executed in another thread using an executor. One is provided in the {@link ThreadManager} class - * A simple thread can't be used in this case because unpredictable errors might happen and some actions might not be executed. + * A simple thread can't be used in this case because overlapping actions might happen and won't be executed. */ public class DBController { @@ -23,7 +23,7 @@ public class DBController { private final static HashMap controllers = new HashMap<>(); - private static MysqlDatabase database = new MysqlDatabase("discord"); + private static MysqlDatabase database = new MysqlDatabase("netneutrality"); /** * @param controller The name of the controller as defined in the {@link AbstractController#getControllerName()}'s method diff --git a/src/main/java/netneutrality/db/MysqlDatabase.java b/src/main/java/netneutrality/db/MysqlDatabase.java index 39315f0..2de9858 100644 --- a/src/main/java/netneutrality/db/MysqlDatabase.java +++ b/src/main/java/netneutrality/db/MysqlDatabase.java @@ -9,8 +9,10 @@ import java.sql.Statement; import java.sql.Timestamp; import java.sql.Types; import java.util.Calendar; +import java.util.function.Consumer; import netneutrality.MusicBot; +import netneutrality.ThreadManager; import netneutrality.db.models.MRowModel; import netneutrality.db.models.MTableModel; import netneutrality.exceptions.UnimplementedParameterException; @@ -18,10 +20,24 @@ import netneutrality.handler.LogHandler; public class MysqlDatabase { + protected enum CommandType { + SELECT("SELECT"), INSERT("INSERT"), UPDATE("UPDATE"), DELETE("DELETE"); + + private String type; + + CommandType(String type) { + this.type = type; + } + + public static CommandType stringToType(String str) { + return CommandType.valueOf(str); + } + } + private Connection connection; private String dbName; - MysqlDatabase(String dbName) { + protected MysqlDatabase(String dbName) { this.dbName = dbName; try { MusicBot.LOGGER.info("Connecting to database..."); @@ -65,7 +81,7 @@ public class MysqlDatabase { public int update(String sql, Object... params) { return executeUpdate(sql, params); } - + /** * Execute an INSERT statement with the specified parameters. * In the SQL query, where there is a parameter to be included, you need to replace it with ? @@ -77,7 +93,7 @@ public class MysqlDatabase { public int insert(String sql, Object... params) { return executeUpdate(sql, params); } - + /** * Execute a DELETE statement with the specified parameters. * In the SQL query, where there is a parameter to be included, you need to replace it with ? @@ -100,7 +116,6 @@ public class MysqlDatabase { } private int executeUpdate(String sql, Object[] params) { - MusicBot.LOGGER.debug("Query: " + sql); try { PreparedStatement query = connection.prepareStatement(sql); @@ -119,7 +134,7 @@ public class MysqlDatabase { * * @param sql The SQL query to execute * @param params The parameters to include in the query - * @return a ResultSet object, which can be converted to an model using {@link MysqlDatabase#convertToTableModel(ResultSet)} + * @return a ResultSet object, which can be converted to a model using {@link MysqlDatabase#convertToTableModel(ResultSet)} */ public ResultSet prepareAndExecute(String sql, Object... params) { MusicBot.LOGGER.debug("Query: " + sql); @@ -129,12 +144,25 @@ public class MysqlDatabase { resolveParameters(query, params); return query.executeQuery(); } catch (SQLException e) { + MusicBot.LOGGER.error(e.toString()); e.printStackTrace(); } return null; } + /** + * Execute a SELECT statement with the specified parameters. + * In the SQL query, where there is a parameter to be included, you need to replace it with ? + * + * @param sql The SQL query to execute + * @param params The parameters to include in the query + * @return a ResultSet object, which can be converted to a model using {@link MysqlDatabase#convertToTableModel(ResultSet)} + */ + public AsyncMySqlAction prepareAndExecuteAsync(String sql, Object... params) { + return new AsyncMySqlAction(this, sql, params); + } + /** * Insert parameters (specified with a ?) in the SQL statement * Taken from https://github.com/Kaaz/DiscordBot/blob/master/src/main/java/emily/db/MySQLAdapter.java#resolveParameters @@ -182,7 +210,7 @@ public class MysqlDatabase { * @throws SQLException */ public void close() throws SQLException { - System.out.println("Closing database..."); + MusicBot.LOGGER.info("Closing database..."); connection.close(); } diff --git a/src/main/java/netneutrality/db/controllers/DBBlacklist.java b/src/main/java/netneutrality/db/controllers/DBBlacklist.java index 29b7294..70ccbd8 100644 --- a/src/main/java/netneutrality/db/controllers/DBBlacklist.java +++ b/src/main/java/netneutrality/db/controllers/DBBlacklist.java @@ -3,8 +3,10 @@ package netneutrality.db.controllers; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; +import netneutrality.MusicBot; import netneutrality.ThreadManager; import netneutrality.db.AbstractController; import netneutrality.db.DBController; @@ -28,26 +30,25 @@ public class DBBlacklist extends AbstractController { } public void add(MBlacklist obj, Consumer success) { - ThreadManager.executor.submit(() -> { - if (!isAlreadyBlacklisted(obj.getWord(), obj.getServerId())) { - database.insert("INSERT INTO blacklist VALUES(?,?,?,?)", obj.getWord(), obj.getServerId(), obj.isEnabled(), obj.getCreatorId()); + isAlreadyBlacklisted(obj.getWord(), obj.getServerId(), blacklisted -> { + if (blacklisted == 0) { + database.prepareAndExecuteAsync("INSERT INTO blacklist VALUES(?,?,?,?)", obj.getWord(), obj.getServerId(), obj.isEnabled(), obj.getCreatorId()).async(); success.accept(true); } else { success.accept(false); } - }); - } public void delete(String word, String serverId, Consumer success) { - ThreadManager.executor.submit(() -> { - if (isAlreadyBlacklisted(word, serverId)) { - System.out.println("true"); - database.delete("DELETE FROM blacklist WHERE word = ? AND serverId = ?", word, serverId); + isAlreadyBlacklisted(word, serverId, blacklisted -> { + if (blacklisted >= 1) { + database.prepareAndExecuteAsync("DELETE FROM blacklist WHERE word = ? AND serverId = ?", word, serverId).async(); + MusicBot.LOGGER.info("blacklisted"); success.accept(true); } else { + MusicBot.LOGGER.info("not blacklisted"); success.accept(false); } }); @@ -56,26 +57,32 @@ public class DBBlacklist extends AbstractController { public void enable(String word, String serverId, Consumer success) { - - ThreadManager.executor.submit(() -> { - if (isAlreadyBlacklisted(word, serverId)) { - database.update("UPDATE blacklist SET isEnabled = 1 WHERE word = ? AND serverId = ?", word, serverId); + isAlreadyBlacklisted(word, serverId, blacklisted -> { + if (blacklisted >= 1) { + database.prepareAndExecuteAsync("UPDATE blacklist SET isEnabled = 1 WHERE word = ? AND serverId = ?", word, serverId).async(); + MusicBot.LOGGER.info("enabled"); success.accept(true); } else { + MusicBot.LOGGER.info("error enabling"); success.accept(false); } }); + } public void disable(String word, String serverId, Consumer success) { - ThreadManager.executor.submit(() -> { - if (isAlreadyBlacklisted(word, serverId)) { - database.update("UPDATE blacklist SET isEnabled = 0 WHERE word = ? AND serverId = ?", word, serverId); + + isAlreadyBlacklisted(word, serverId, blacklisted -> { + if (blacklisted >= 1) { + database.prepareAndExecuteAsync("UPDATE blacklist SET isEnabled = 0 WHERE word = ? AND serverId = ?", word, serverId).async(); + MusicBot.LOGGER.info("disabled"); success.accept(true); } else { + MusicBot.LOGGER.info("error disabled"); success.accept(false); } }); + } public void getBlacklistForWord(String word, String serverId, Consumer success) { @@ -84,7 +91,7 @@ public class DBBlacklist extends AbstractController { if (isAlreadyBlacklisted(word, serverId)) { ResultSet rs = database.prepareAndExecute("SELECT * FROM blacklist WHERE word = ? AND serverId = ?", word, serverId); - MTableModel table = database.convertToTableModel(rs); + MTableModel table = MysqlDatabase.convertToTableModel(rs); if (table.getNbRows() > 0) { blacklisted = new MBlacklist((String) table.getRow(0).get(0), (Boolean) table.getRow(0).get(2), (String) table.getRow(0).get(3), @@ -98,42 +105,44 @@ public class DBBlacklist extends AbstractController { } public void getBlacklistFromServer(String serverId, Consumer> success) { - ThreadManager.executor.submit(() -> { + + database.prepareAndExecuteAsync("SELECT * FROM blacklist WHERE serverId = ? AND isEnabled = 1", serverId).async(model -> { ArrayList output = new ArrayList<>(); - try { - ResultSet rs = database.prepareAndExecute("SELECT * FROM blacklist WHERE serverId = ? AND isEnabled = 1", serverId); - MTableModel model = MysqlDatabase.convertToTableModel(rs); - - if (model.getNbRows() != 0) { - for (int row = 0; row < model.getNbRows(); row++) { - output.add(new MBlacklist((String) model.getRow(row).get(0), (Boolean) model.getRow(row).get(2), (String) model.getRow(row).get(3), - (String) model.getRow(row).get(1))); - } - } else { - throw new RuntimeException("Blacklist is empty"); + if (model.getNbRows() != 0) { + for (int row = 0; row < model.getNbRows(); row++) { + output.add(new MBlacklist((String) model.getRow(row).get(0), (Boolean) model.getRow(row).get(2), (String) model.getRow(row).get(3), + (String) model.getRow(row).get(1))); } - - } catch (NullPointerException | IndexOutOfBoundsException ignored) { } + } success.accept(output); }); } - public boolean isAlreadyBlacklisted(String word, String serverId) { - ResultSet rs = database.prepareAndExecute("SELECT COUNT(*) FROM blacklist WHERE word = ? AND serverId = ?", word, serverId); + @Deprecated + private boolean isAlreadyBlacklisted(String word, String serverId) { + AtomicBoolean result = new AtomicBoolean(); - try { - if (rs.next()) { - return rs.getInt(1) != 0; + database.prepareAndExecuteAsync("SELECT COUNT(*) FROM blacklist WHERE word = ? AND serverId = ?", word, serverId).async(table -> { + if (!table.isEmpty()) { + result.set((int) table.getRowModel(0).getItem(0) != 0); } - } catch (SQLException e) { - //TODO: error log - e.printStackTrace(); - } + }); - return false; + return result.get(); + } + + private void isAlreadyBlacklisted(String word, String serverId, Consumer result) { + + database.prepareAndExecuteAsync("SELECT COUNT(*) FROM blacklist WHERE word = ? AND serverId = ?", word, serverId).async(table -> { + if (!table.isEmpty()) { + int count = Integer.parseInt(table.getRowModel(0).getItem(0).toString()); + + result.accept(count); + } + }); } @Override diff --git a/src/main/java/netneutrality/db/controllers/DBMessage.java b/src/main/java/netneutrality/db/controllers/DBMessage.java index 0ad205f..91c8faf 100644 --- a/src/main/java/netneutrality/db/controllers/DBMessage.java +++ b/src/main/java/netneutrality/db/controllers/DBMessage.java @@ -28,18 +28,12 @@ public class DBMessage extends AbstractController { } public void log(String servername, String channelname, String username, String datesent, String messageId, String message) { - - ThreadManager.executor.submit(() -> { - database.insert("INSERT INTO log_message VALUES(?,?,?,?,?,?,?)", servername, channelname, username, datesent, messageId, message, null); - }); + database.prepareAndExecuteAsync("INSERT INTO log_message VALUES(?,?,?,?,?,?,?)", servername, channelname, username, datesent, messageId, message, null).async(); } public void logEdit(String messageId, String newMessage) { - - ThreadManager.executor.submit(() -> { - database.update("UPDATE log_message SET editedMessage = ? WHERE messageId = ?", newMessage, messageId); - }); + database.prepareAndExecuteAsync("UPDATE log_message SET editedMessage = ? WHERE messageId = ?", newMessage, messageId).async(); } diff --git a/src/main/java/netneutrality/db/controllers/DBSettings.java b/src/main/java/netneutrality/db/controllers/DBSettings.java index 96a4185..df5c4ba 100644 --- a/src/main/java/netneutrality/db/controllers/DBSettings.java +++ b/src/main/java/netneutrality/db/controllers/DBSettings.java @@ -1,10 +1,8 @@ package netneutrality.db.controllers; -import java.sql.ResultSet; -import java.sql.SQLException; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; -import netneutrality.ThreadManager; import netneutrality.db.AbstractController; import netneutrality.db.MysqlDatabase; import netneutrality.db.models.MTableModel; @@ -13,26 +11,21 @@ public class DBSettings extends AbstractController { public void getSettingsByKey(String key, Consumer success) { - ThreadManager.executor.submit(() -> { - Object value = null; + database.prepareAndExecuteAsync("SELECT value FROM settings WHERE skey = ?", key).async(table -> { + Object value = null; - ResultSet rs; - rs = database.prepareAndExecute("SELECT value FROM settings WHERE skey = ?", key); - MTableModel table = MysqlDatabase.convertToTableModel(rs); + if (table.getNbRows() == 1) { + value = table.getRowModel(0).getItem(0); + } - if (table.getNbRows() == 1) { - value = table.getRowModel(0).getItem(0); - } - - success.accept(value); - }); + success.accept(value); + }); } + @Deprecated public String getSettingsByKey(String key) { - ResultSet rs; - rs = database.prepareAndExecute("SELECT value FROM settings WHERE skey = ?", key); - MTableModel table = MysqlDatabase.convertToTableModel(rs); + MTableModel table = database.prepareAndExecuteAsync("SELECT value FROM settings WHERE skey = ?", key).blocking(); if (table.getNbRows() == 1) { return table.getRow(0).get(0).toString();