From 00f541dafe69b35510bfc9e9b45d309c94dfe1a7 Mon Sep 17 00:00:00 2001 From: Sn0wStorm Date: Thu, 23 Jan 2020 22:18:14 +0100 Subject: [PATCH] Created Async MySQL Saver --- src/com/dre/brewery/BPlayer.java | 7 + src/com/dre/brewery/P.java | 9 + src/com/dre/brewery/filedata/BConfig.java | 33 ++++ src/com/dre/brewery/utility/SQLSync.java | 225 ++++++++++++++++++++++ 4 files changed, 274 insertions(+) create mode 100644 src/com/dre/brewery/utility/SQLSync.java diff --git a/src/com/dre/brewery/BPlayer.java b/src/com/dre/brewery/BPlayer.java index bb23ceb..bf268a5 100644 --- a/src/com/dre/brewery/BPlayer.java +++ b/src/com/dre/brewery/BPlayer.java @@ -723,4 +723,11 @@ public class BPlayer { return -getQuality() + 11; } + /** + * Drunkeness at the time he went offline + */ + public int getOfflineDrunkeness() { + return offlineDrunk; + } + } diff --git a/src/com/dre/brewery/P.java b/src/com/dre/brewery/P.java index 8ef2bea..b215773 100644 --- a/src/com/dre/brewery/P.java +++ b/src/com/dre/brewery/P.java @@ -23,6 +23,7 @@ import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.event.HandlerList; import org.bukkit.plugin.java.JavaPlugin; +import java.sql.SQLException; import java.util.HashMap; import java.util.Map; @@ -151,6 +152,14 @@ public class P extends JavaPlugin { // save Data to Disk DataSave.save(true); + if (BConfig.sqlSync != null) { + try { + BConfig.sqlSync.closeConnection(); + } catch (SQLException ignored) { + } + BConfig.sqlSync = null; + } + // delete config data, in case this is a reload and to clear up some ram clearConfigData(); diff --git a/src/com/dre/brewery/filedata/BConfig.java b/src/com/dre/brewery/filedata/BConfig.java index 5588440..052b952 100644 --- a/src/com/dre/brewery/filedata/BConfig.java +++ b/src/com/dre/brewery/filedata/BConfig.java @@ -17,6 +17,7 @@ import com.dre.brewery.recipe.BRecipe; import com.dre.brewery.recipe.PluginItem; import com.dre.brewery.recipe.RecipeItem; import com.dre.brewery.utility.BUtil; +import com.dre.brewery.utility.SQLSync; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.command.CommandSender; @@ -29,6 +30,7 @@ import org.bukkit.plugin.PluginManager; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -76,6 +78,12 @@ public class BConfig { //Item public static List customItems = new ArrayList<>(); + //MySQL + public static String sqlHost, sqlPort, sqlDB; + private static String sqlUser, sqlPW; + public static SQLSync sqlSync; + public static boolean sqlDrunkSync; + public static P p = P.p; private static boolean checkConfigs() { @@ -322,6 +330,31 @@ public class BConfig { DistortChat.log = config.getBoolean("logRealChat", false); DistortChat.doSigns = config.getBoolean("distortSignText", false); + // init SQL + if (sqlSync != null) { + try { + sqlSync.closeConnection(); + } catch (SQLException ignored) { + } + sqlSync = null; + } + sqlDrunkSync = false; + + ConfigurationSection sqlCfg = config.getConfigurationSection("multiServerDB"); + if (sqlCfg != null && sqlCfg.getBoolean("enabled")) { + sqlDrunkSync = sqlCfg.getBoolean("syncDrunkeness"); + sqlHost = sqlCfg.getString("host", null); + sqlPort = sqlCfg.getString("port", null); + sqlUser = sqlCfg.getString("user", null); + sqlDB = sqlCfg.getString("database", null); + sqlPW = sqlCfg.getString("password", null); + + sqlSync = new SQLSync(); + if (!sqlSync.init(sqlUser, sqlPW)) { + sqlSync = null; + } + } + // The Config was reloaded, call Event ConfigLoadEvent event = new ConfigLoadEvent(); P.p.getServer().getPluginManager().callEvent(event); diff --git a/src/com/dre/brewery/utility/SQLSync.java b/src/com/dre/brewery/utility/SQLSync.java new file mode 100644 index 0000000..cf4f37c --- /dev/null +++ b/src/com/dre/brewery/utility/SQLSync.java @@ -0,0 +1,225 @@ +package com.dre.brewery.utility; + +import com.dre.brewery.BPlayer; +import com.dre.brewery.P; +import com.dre.brewery.filedata.BConfig; +import org.bukkit.entity.Player; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.UUID; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; + +public class SQLSync { + private BlockingQueue saveDataQueue = new ArrayBlockingQueue<>(64); + private static boolean sqlTaskRunning = false; + + private Connection connection; + private String connector; + private String user, password; + + + public void updatePlayer(Player player, BPlayer bPlayer) { + removePlayer(player.getUniqueId()); + SQLData_BP bP = new SQLData_BP(); + bP.uuid = player.getUniqueId(); + bP.drunkeness = bPlayer.getDrunkeness(); + bP.offlineDrunk = bPlayer.getOfflineDrunkeness(); + bP.quality = bPlayer.getQuality(); + bP.data = null; + + addSaveData(bP); + } + + public void updateData(String name, String data) { + removeData(name); + SQLData_BD bD = new SQLData_BD(); + bD.name = name; + bD.data = data; + + addSaveData(bD); + } + + public void removePlayer(UUID uuid) { + SQLRemove_BP r = new SQLRemove_BP(); + r.uuid = uuid; + + addSaveData(r); + } + + public void removeData(String name) { + SQLRemove_BD r = new SQLRemove_BD(); + r.name = name; + + addSaveData(r); + } + + private void addSaveData(Object object) { + initAsyncTask(); + try { + if (!saveDataQueue.offer(object, 5, TimeUnit.SECONDS)) { + BConfig.sqlSync = null; + closeConnection(); + P.p.errorLog("SQL saving queue overrun, disabling SQL saving"); + } + } catch (InterruptedException | SQLException e) { + e.printStackTrace(); + } + } + + private void initAsyncTask() { + if (sqlTaskRunning) return; + sqlTaskRunning = true; + P.p.getServer().getScheduler().runTaskAsynchronously(P.p, new SQLSaver()); + } + + + public boolean init(String user, String password) { + this.user = user; + this.password = password; + + if (BConfig.sqlHost == null || BConfig.sqlPort == null || user == null || BConfig.sqlDB == null || password == null) { + P.p.errorLog("Mysql settings not correctly defined!"); + return false; + } + + try { + Class.forName("com.mysql.jdbc.Driver"); + String str = "jdbc:mysql://" + BConfig.sqlHost + ":" + BConfig.sqlPort + "/" + BConfig.sqlDB; + connection = DriverManager.getConnection(str, user, password); + + Statement statement = connection.createStatement(); + statement.execute("CREATE TABLE IF NOT EXISTS BreweryZ_BPlayers (" + + "uuid CHAR(36) NOT NULL, " + + "quality INT, " + + "drunkeness INT, " + + "offlineDrunk INT, " + + "data VARCHAR(127), " + + "PRIMARY KEY (uuid));"); + statement = connection.createStatement(); + statement.execute("CREATE TABLE IF NOT EXISTS BreweryZ_BData (" + + "id SMALLINT AUTOINCREMENT, " + + "name VARCHAR(127) NOT NULL UNIQUE, " + + "data TEXT, " + + "PRIMARY KEY (id));"); + + connector = str; + } catch (SQLException | ClassNotFoundException e) { + e.printStackTrace(); + return false; + } + + return true; + } + + public boolean openConnection() { + if (connector == null) { + return false; + } + try { + connection = DriverManager.getConnection(connector, user, password); + } catch (SQLException e) { + e.printStackTrace(); + return false; + } + return true; + } + + public boolean checkConnection() throws SQLException { + return connection != null && !connection.isClosed(); + } + + synchronized public boolean closeConnection() throws SQLException { + if (connection == null) { + return false; + } + connection.close(); + return true; + } + + private static class SQLData_BP { + public UUID uuid; + public int quality; + public int drunkeness; + public int offlineDrunk; + public String data; + } + + private static class SQLData_BD { + public String name; + public String data; + } + + private static class SQLRemove_BP { + public UUID uuid; + } + + private static class SQLRemove_BD { + public String name; + } + + private class SQLSaver implements Runnable { + + @Override + public void run() { + try { + while (true) { + try { + Object o = saveDataQueue.take(); // Wait for next element in queue + + if (!checkConnection()) { + if (!openConnection()) { + P.p.errorLog("Opening SQL Connection failed"); + return; + } + } + + if (o instanceof SQLData_BP) { + SQLData_BP d = ((SQLData_BP) o); + PreparedStatement ps = connection.prepareStatement("INSERT INTO BreweryZ_BPlayers (uuid, quality, drunkeness, offlineDrunk, data) VALUES (?, ?, ?, ?, ?);"); + ps.setString(1, d.uuid.toString()); + ps.setInt(2, d.quality); + ps.setInt(3, d.drunkeness); + ps.setInt(4, d.offlineDrunk); + ps.setString(5, d.data); + + ps.executeUpdate(); + } else if (o instanceof SQLData_BD) { + SQLData_BD d = ((SQLData_BD) o); + PreparedStatement ps = connection.prepareStatement("INSERT INTO BreweryZ_BData (name, data) VALUES (?, ?);"); + ps.setString(1, d.name); + ps.setString(2, d.data); + + ps.executeUpdate(); + } else if (o instanceof SQLRemove_BP) { + SQLRemove_BP r = ((SQLRemove_BP) o); + PreparedStatement ps = connection.prepareStatement("DELETE FROM BreweryZ_BPlayers WHERE uuid = ?;"); + ps.setString(1, r.uuid.toString()); + + ps.executeUpdate(); + } else if (o instanceof SQLRemove_BD) { + SQLRemove_BD r = ((SQLRemove_BD) o); + PreparedStatement ps = connection.prepareStatement("DELETE FROM BreweryZ_BData WHERE name = ?;"); + ps.setString(1, r.name); + + ps.executeUpdate(); + } + + } catch (InterruptedException e) { + return; + } catch (Exception e) { + e.printStackTrace(); + } + } + } finally { + sqlTaskRunning = false; + } + } + } + +}