TF-Marriage/src/main/java/com/lenis0012/bukkit/marriage2/internal/data/DataManager.java

422 lines
18 KiB
Java
Raw Normal View History

2014-11-13 16:45:41 +00:00
package com.lenis0012.bukkit.marriage2.internal.data;
2016-02-23 20:58:24 +00:00
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
2015-05-26 21:58:01 +00:00
import com.google.common.collect.Lists;
2016-02-26 19:57:48 +00:00
import com.google.common.collect.Sets;
2016-04-21 07:39:59 +00:00
import com.lenis0012.bukkit.marriage2.MData;
import com.lenis0012.bukkit.marriage2.internal.MarriageCore;
2016-02-26 19:57:48 +00:00
import com.lenis0012.bukkit.marriage2.internal.MarriagePlugin;
2016-02-25 14:11:32 +00:00
import com.lenis0012.bukkit.marriage2.misc.BConfig;
2016-04-21 07:39:59 +00:00
import com.lenis0012.bukkit.marriage2.misc.ListQuery;
2016-02-23 10:55:39 +00:00
import com.lenis0012.bukkit.marriage2.misc.LockedReference;
2015-07-08 12:17:26 +00:00
import org.bukkit.Bukkit;
2014-11-13 16:45:41 +00:00
import org.bukkit.configuration.file.FileConfiguration;
2015-07-08 12:17:26 +00:00
import org.bukkit.entity.Player;
2014-11-13 16:45:41 +00:00
2016-04-21 07:39:59 +00:00
import java.io.File;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
2014-11-13 16:45:41 +00:00
public class DataManager {
2016-02-28 14:48:53 +00:00
private static final ExecutorService executorService = Executors.newCachedThreadPool();
public static ExecutorService getExecutorService() {
return executorService;
}
2016-02-23 20:58:24 +00:00
// Create a data cache to overlap with the pre join event cache
private final Cache<UUID, MarriageData> marriageDataCache = CacheBuilder.newBuilder().expireAfterWrite(60L, TimeUnit.SECONDS).build();
2016-02-25 14:11:32 +00:00
private final MarriageCore core;
2016-06-14 14:39:44 +00:00
private LockedReference supplier;
private String prefix;
2016-02-25 14:11:32 +00:00
public DataManager(MarriageCore core) {
this.core = core;
File configFile = new File(core.getPlugin().getDataFolder(), "database-settings.yml");
2020-12-04 02:54:18 +00:00
if (!configFile.exists()) {
2016-02-25 14:11:32 +00:00
BConfig.copyFile(core.getPlugin().getResource("database-settings.yml"), configFile);
}
FileConfiguration config = core.getBukkitConfig("database-settings.yml");
Driver driver = config.getBoolean("MySQL.enabled") ? Driver.MYSQL : Driver.SQLITE;
loadWithDriver(driver, config);
}
2016-06-14 14:39:44 +00:00
public DataManager(MarriageCore core, Driver driver) {
this.core = core;
2016-02-25 14:11:32 +00:00
FileConfiguration config = core.getBukkitConfig("database-settings.yml");
loadWithDriver(driver, config);
2016-06-14 14:39:44 +00:00
}
2015-07-10 15:02:50 +00:00
2016-02-25 14:11:32 +00:00
public void close() {
supplier.invalidateNow();
}
2016-02-23 10:55:39 +00:00
2016-02-25 14:11:32 +00:00
private void loadWithDriver(Driver driver, FileConfiguration config) {
2017-11-23 19:04:02 +00:00
String url, user = "", password = "";
2020-12-04 02:54:18 +00:00
if (driver == Driver.MYSQL) {
2017-11-23 19:04:02 +00:00
user = config.getString("MySQL.user", "root");
password = config.getString("MySQL.password", "");
2016-02-25 14:11:32 +00:00
String host = config.getString("MySQL.host", "localhost:3306");
String database = config.getString("MySQL.database", "myserver");
this.prefix = config.getString("MySQL.prefix", "marriage_");
2017-11-23 19:04:02 +00:00
url = String.format("jdbc:mysql://%s/%s", host, database);
2016-02-25 14:11:32 +00:00
driver = Driver.MYSQL;
} else {
url = String.format("jdbc:sqlite:%s", new File(core.getPlugin().getDataFolder(), "database.db").getPath());
this.prefix = "";
}
2016-02-23 10:55:39 +00:00
2016-02-26 19:57:48 +00:00
// Purge system
2020-12-04 02:54:18 +00:00
if (config.getBoolean("auto-purge.enabled")) {
2016-02-26 19:57:48 +00:00
final long delayTime = 20L * 60 * 60; // Every hour
final int days = config.getInt("auto-purge.purge-after-days", 45);
final boolean purgeMarried = config.getBoolean("auto-purge.purge-married-players", false);
final long daysInMillis = days * 24 * 60 * 60 * 1000L;
2016-03-06 23:09:03 +00:00
Bukkit.getScheduler().runTaskTimerAsynchronously(MarriagePlugin.getCore().getPlugin(), new Runnable() {
2016-02-26 19:57:48 +00:00
@Override
public void run() {
long startTime = System.currentTimeMillis();
int purged = purge(daysInMillis, purgeMarried);
long duration = System.currentTimeMillis() - startTime;
2020-12-04 02:54:18 +00:00
if (purged > 0) {
2020-05-21 10:52:29 +00:00
core.getLogger().log(Level.INFO, "Purged " + purged + " player entries in " + duration + "ms");
}
2016-02-26 19:57:48 +00:00
}
}, 0L, delayTime);
}
2016-02-25 14:11:32 +00:00
try {
driver.initiate();
2020-12-04 02:54:18 +00:00
} catch (Exception e) {
2016-02-25 14:11:32 +00:00
core.getLogger().log(Level.SEVERE, "Failed to initiate database driver", e);
}
// Create cached connection supplier.
2017-11-23 19:04:02 +00:00
this.supplier = new LockedReference(new ConnectionSupplier(url, user, password), 30L, TimeUnit.SECONDS, new ConnectionInvalidator());
2016-02-25 14:11:32 +00:00
DBUpgrade upgrade = new DBUpgrade();
Connection connection = supplier.access();
try {
Statement statement = connection.createStatement();
driver.runSetup(statement, prefix);
ResultSet result = statement.executeQuery(String.format("SELECT * FROM %sversion;", prefix));
2020-12-04 02:54:18 +00:00
if (result.next()) {
2016-02-25 14:11:32 +00:00
int dbVersion = result.getInt("version_id");
2020-12-04 02:54:18 +00:00
if (dbVersion >= 2) {
2016-03-01 00:59:03 +00:00
// Fix for people that first installed on v2
DatabaseMetaData metadata = connection.getMetaData();
ResultSet res = metadata.getColumns(null, null, prefix + "players", "last_name");
2020-12-04 02:54:18 +00:00
if (!res.next()) {
2016-03-01 00:59:03 +00:00
statement.execute("ALTER TABLE " + prefix + "players ADD last_name VARCHAR(16);");
}
}
2020-12-04 02:54:18 +00:00
if (dbVersion < upgrade.getVersionId()) {
2016-02-27 23:57:54 +00:00
upgrade.run(statement, dbVersion, prefix);
PreparedStatement ps = connection.prepareStatement("UPDATE " + prefix + "version SET version_id=? WHERE version_id=?;");
ps.setInt(1, upgrade.getVersionId());
ps.setInt(2, dbVersion);
ps.executeUpdate();
2016-02-25 14:11:32 +00:00
}
} else {
statement.executeUpdate(String.format("INSERT INTO %sversion (version_id) VALUES(%s);", prefix, upgrade.getVersionId()));
}
2020-12-04 02:54:18 +00:00
} catch (SQLException e) {
2016-02-25 14:11:32 +00:00
core.getLogger().log(Level.WARNING, "Failed to initiate database", e);
} finally {
supplier.finish();
}
}
2016-02-26 19:57:48 +00:00
private int purge(long daysInMillis, boolean purgeMarried) {
String query = String.format("SELECT * FROM %splayers WHERE lastlogin < ?;", prefix);
Connection connection = supplier.access();
try {
PreparedStatement ps = connection.prepareStatement(query);
ps.setLong(1, System.currentTimeMillis() - daysInMillis);
ResultSet result = ps.executeQuery();
Set<String> removeList = Sets.newHashSet();
Set<Integer> removeList2 = Sets.newHashSet();
2020-12-04 02:54:18 +00:00
while (result.next()) {
2016-02-26 19:57:48 +00:00
removeList.add(result.getString("unique_user_id"));
}
ps.close(); // Release statement
supplier.finish(); // Let queued actions run first
2020-12-04 02:54:18 +00:00
if (!purgeMarried) {
2016-02-26 19:57:48 +00:00
connection = supplier.access();
ps = connection.prepareStatement("SELECT * FROM " + prefix + "marriages;");
result = ps.executeQuery();
2020-12-04 02:54:18 +00:00
while (result.next()) {
2016-02-26 19:57:48 +00:00
boolean remove = removeList.remove(result.getString("player1"));
remove = remove || removeList.remove(result.getString("player2"));
2020-12-04 02:54:18 +00:00
if (remove) {
2016-02-26 19:57:48 +00:00
removeList2.add(result.getInt("id"));
}
}
ps.close(); // Release statement
supplier.finish(); // Let queued actions run first
}
// Delete player entries
connection = supplier.access();
ps = connection.prepareStatement("DELETE FROM " + prefix + "players WHERE unique_user_id=?;");
2020-12-04 02:54:18 +00:00
for (String uuid : removeList) {
2016-02-26 19:57:48 +00:00
ps.setString(1, uuid);
ps.addBatch();
}
ps.executeBatch();
ps.close();
supplier.finish();
// Remove marriage entries
connection = supplier.access();
ps = connection.prepareStatement("DELETE FROM " + prefix + "marriages WHERE id=?;");
2020-12-04 02:54:18 +00:00
for (int id : removeList2) {
2016-02-26 19:57:48 +00:00
ps.setInt(1, id);
ps.addBatch();
}
ps.executeBatch();
ps.close();
return removeList.size();
2020-12-04 02:54:18 +00:00
} catch (SQLException e) {
2016-02-26 19:57:48 +00:00
core.getLogger().log(Level.WARNING, "Failed to purge user data", e);
return 0;
} finally {
supplier.finish();
}
}
2016-06-14 14:39:44 +00:00
public MarriagePlayer loadPlayer(UUID uuid) {
MarriagePlayer player = null;
Connection connection = supplier.access();
try {
PreparedStatement ps = connection.prepareStatement(String.format(
"SELECT * FROM %splayers WHERE unique_user_id=?;", prefix));
ps.setString(1, uuid.toString());
player = new MarriagePlayer(uuid, ps.executeQuery());
2016-02-26 19:57:48 +00:00
ps.close(); // Release statement
2016-06-14 14:39:44 +00:00
loadMarriages(connection, player, false);
2020-12-04 02:54:18 +00:00
} catch (SQLException e) {
2016-06-14 14:39:44 +00:00
core.getLogger().log(Level.WARNING, "Failed to load player data", e);
} finally {
supplier.finish();
}
return player;
}
public void savePlayer(MarriagePlayer player) {
2020-12-04 02:54:18 +00:00
if (player == null || player.getUniqueId() == null) return;
2016-06-14 14:39:44 +00:00
Connection connection = supplier.access();
try {
PreparedStatement ps = connection.prepareStatement(String.format(
"SELECT * FROM %splayers WHERE unique_user_id=?;", prefix));
ps.setString(1, player.getUniqueId().toString());
ResultSet result = ps.executeQuery();
2020-12-04 02:54:18 +00:00
if (result.next()) {
2016-06-14 14:39:44 +00:00
// Already in database (update)
PreparedStatement ps2 = connection.prepareStatement(String.format(
"UPDATE %splayers SET last_name=?,gender=?,priest=?,lastlogin=? WHERE unique_user_id=?;", prefix));
2016-02-27 23:57:54 +00:00
ps2.setString(1, player.getLastName());
2016-06-14 14:39:44 +00:00
ps2.setString(2, player.getGender().toString());
ps2.setBoolean(3, player.isPriest());
ps2.setLong(4, System.currentTimeMillis());
ps2.setString(5, player.getUniqueId().toString());
ps2.executeUpdate();
2016-02-26 19:57:48 +00:00
ps2.close();
2016-06-14 14:39:44 +00:00
} else {
// Not in database yet
PreparedStatement ps2 = connection.prepareStatement(String.format(
"INSERT INTO %splayers (unique_user_id,last_name,gender,priest,lastlogin) VALUES(?,?,?,?,?);", prefix));
player.save(ps2);
ps2.executeUpdate();
2016-02-26 19:57:48 +00:00
ps2.close();
2016-06-14 14:39:44 +00:00
}
2016-02-26 19:57:48 +00:00
ps.close();
2020-12-04 02:54:18 +00:00
} catch (SQLException e) {
2016-06-14 14:39:44 +00:00
core.getLogger().log(Level.WARNING, "Failed to save player data", e);
} finally {
supplier.finish();
}
}
2016-02-23 20:58:24 +00:00
public void saveMarriage(MarriageData mdata) {
Connection connection = supplier.access();
try {
PreparedStatement ps = connection.prepareStatement(String.format("SELECT * FROM %smarriages WHERE player1=? AND player2=?;", prefix));
ps.setString(1, mdata.getPlayer1Id().toString());
ps.setString(2, mdata.getPllayer2Id().toString());
ResultSet result = ps.executeQuery();
2020-12-04 02:54:18 +00:00
if (result.next()) {
2016-02-23 20:58:24 +00:00
// Update existing entry
2016-02-26 19:57:48 +00:00
PreparedStatement ps2 = connection.prepareStatement(String.format(
2016-02-23 20:58:24 +00:00
"UPDATE %smarriages SET player1=?,player2=?,home_world=?,home_x=?,home_y=?,home_z=?,home_yaw=?,home_pitch=?,pvp_enabled=? WHERE id=?;", prefix));
2016-02-26 19:57:48 +00:00
mdata.save(ps2);
ps2.setInt(10, mdata.getId());
ps2.executeUpdate();
ps2.close();
2016-02-23 20:58:24 +00:00
} else {
2016-02-26 19:57:48 +00:00
PreparedStatement ps2 = connection.prepareStatement(String.format(
2016-02-23 20:58:24 +00:00
"INSERT INTO %smarriages (player1,player2,home_world,home_x,home_y,home_z,home_yaw,home_pitch,pvp_enabled) VALUES(?,?,?,?,?,?,?,?,?);", prefix));
2016-02-26 19:57:48 +00:00
mdata.save(ps2);
ps2.executeUpdate();
ps2.close();
2016-02-23 20:58:24 +00:00
}
2020-12-04 02:54:18 +00:00
} catch (SQLException e) {
2016-02-23 20:58:24 +00:00
core.getLogger().log(Level.WARNING, "Failed to save marriage data", e);
} finally {
supplier.finish();
}
}
2016-06-14 14:39:44 +00:00
private void loadMarriages(Connection connection, MarriagePlayer player, boolean alt) throws SQLException {
PreparedStatement ps = connection.prepareStatement(String.format(
"SELECT * FROM %smarriages WHERE %s=?;", prefix, alt ? "player2" : "player1", prefix));
ps.setString(1, player.getUniqueId().toString());
ResultSet result = ps.executeQuery();
2020-12-04 02:54:18 +00:00
while (result.next()) {
2016-06-14 14:39:44 +00:00
UUID partnerId = UUID.fromString(result.getString(alt ? "player1" : "player2"));
Player partner = Bukkit.getPlayer(partnerId);
2016-02-23 20:58:24 +00:00
MarriageData data;
2020-12-04 02:54:18 +00:00
if (partner != null && partner.isOnline() && core.isMPlayerSet(partner.getUniqueId())) {
2016-06-14 14:39:44 +00:00
// Copy marriage data from partner to ensure a match.
data = (MarriageData) core.getMPlayer(partner).getMarriage();
2020-12-04 02:54:18 +00:00
} else if ((data = marriageDataCache.getIfPresent(player.getUniqueId())) == null) {
2016-02-23 20:58:24 +00:00
data = new MarriageData(this, result);
marriageDataCache.put(data.getPlayer1Id(), data);
marriageDataCache.put(data.getPllayer2Id(), data);
}
player.addMarriage(data);
2016-06-14 14:39:44 +00:00
}
2016-02-26 19:57:48 +00:00
ps.close();
2016-06-14 14:39:44 +00:00
2020-12-04 02:54:18 +00:00
if (!alt) {
2016-06-14 14:39:44 +00:00
loadMarriages(connection, player, true);
}
}
2015-07-10 15:02:50 +00:00
public void deleteMarriage(UUID player1, UUID player2) {
2016-02-23 10:55:39 +00:00
Connection connection = supplier.access();
2015-07-10 15:02:50 +00:00
try {
2016-02-23 12:23:38 +00:00
PreparedStatement ps = connection.prepareStatement(String.format("DELETE FROM %smarriages WHERE player1=? AND player2=?;", prefix));
2015-07-10 15:02:50 +00:00
ps.setString(1, player1.toString());
ps.setString(2, player2.toString());
ps.executeUpdate();
2016-02-26 19:57:48 +00:00
ps.close();
2020-12-04 02:54:18 +00:00
} catch (SQLException e) {
2015-07-10 15:02:50 +00:00
core.getLogger().log(Level.WARNING, "Failed to load player data", e);
} finally {
2016-02-23 10:55:39 +00:00
supplier.finish();
2015-07-10 15:02:50 +00:00
}
}
2016-06-14 14:39:44 +00:00
public ListQuery listMarriages(int scale, int page) {
Connection connection = supplier.access();
try {
// Count rows to get amount of pages
PreparedStatement ps = connection.prepareStatement("SELECT COUNT(*) FROM " + prefix + "marriages;");
ResultSet result = ps.executeQuery();
result.next();
int pages = (int) Math.ceil(result.getInt(1) / (double) scale);
// Fetch te right page
ps = connection.prepareStatement(String.format(
"SELECT * FROM %smarriages LIMIT %s OFFSET %s;", prefix, scale, scale * page));
2015-05-26 21:58:01 +00:00
//"SELECT * FROM %sdata ORDER BY id DESC LIMIT %s OFFSET %s;", prefix, scale, scale * page));
2016-06-14 14:39:44 +00:00
result = ps.executeQuery();
List<MData> list = Lists.newArrayList();
2020-12-04 02:54:18 +00:00
while (result.next()) {
2016-06-14 14:39:44 +00:00
list.add(new MarriageData(this, result));
}
2016-02-26 19:57:48 +00:00
ps.close();
2016-06-14 14:39:44 +00:00
return new ListQuery(this, pages, page, list);
2020-12-04 02:54:18 +00:00
} catch (SQLException e) {
2016-06-14 14:39:44 +00:00
core.getLogger().log(Level.WARNING, "Failed to load marriage list", e);
return new ListQuery(this, 0, 0, new ArrayList<MData>());
} finally {
supplier.finish();
}
}
2016-02-23 10:55:39 +00:00
2016-02-25 14:11:32 +00:00
public boolean migrateTo(DataManager db, boolean migrateUnmarriedPlayers) {
Connection connection = supplier.access();
try {
// Migrate players
core.getLogger().log(Level.INFO, "Migrating player data... (may take A WHILE)");
PreparedStatement ps = connection.prepareStatement("SELECT * FROM " + prefix + "players;");
ResultSet result = ps.executeQuery();
2020-12-04 02:54:18 +00:00
while (result.next()) {
2016-02-25 14:11:32 +00:00
UUID uuid = UUID.fromString(result.getString("unique_user_id"));
MarriagePlayer player = new MarriagePlayer(uuid, result);
2020-12-04 02:54:18 +00:00
if (!player.isMarried() && !migrateUnmarriedPlayers) continue;
2016-02-25 14:11:32 +00:00
db.savePlayer(player);
}
2016-02-26 19:57:48 +00:00
ps.close();
2016-02-25 14:11:32 +00:00
2016-02-26 19:57:48 +00:00
core.getLogger().log(Level.INFO, "Migrating marriage data...");
2016-02-25 14:11:32 +00:00
ps = connection.prepareStatement("SELECT * FROM " + prefix + "marriages;");
result = ps.executeQuery();
2020-12-04 02:54:18 +00:00
while (result.next()) {
2016-02-25 14:11:32 +00:00
MarriageData data = new MarriageData(this, result);
db.saveMarriage(data);
}
2016-02-26 19:57:48 +00:00
ps.close();
2016-02-25 14:11:32 +00:00
core.getLogger().log(Level.INFO, "Migration complete!");
return true;
2020-12-04 02:54:18 +00:00
} catch (SQLException e) {
2016-02-25 14:11:32 +00:00
core.getLogger().log(Level.WARNING, "Failed to load migrate database", e);
} finally {
supplier.finish();
}
return false;
}
2016-06-14 14:39:44 +00:00
public static final class ConnectionSupplier {
private final String url;
2017-11-23 19:04:02 +00:00
private final String user;
private final String password;
2016-06-14 14:39:44 +00:00
private ConnectionSupplier(String url) {
2017-11-23 19:04:02 +00:00
this(url, "", "");
}
private ConnectionSupplier(String url, String user, String password) {
2016-06-14 14:39:44 +00:00
this.url = url;
2017-11-23 19:04:02 +00:00
this.user = user;
this.password = password;
2016-06-14 14:39:44 +00:00
}
public Connection get() {
try {
2017-11-23 19:04:02 +00:00
return DriverManager.getConnection(url, user, password);
2020-12-04 02:54:18 +00:00
} catch (SQLException e) {
2016-06-14 14:39:44 +00:00
return null;
}
}
}
public static final class ConnectionInvalidator {
public void accept(Connection connection) {
// Try to close connection
try {
connection.close();
2020-12-04 02:54:18 +00:00
} catch (SQLException e) {
2016-06-14 14:39:44 +00:00
}
}
}
2014-11-13 16:45:41 +00:00
}