mirror of
https://github.com/LuckPerms/LuckPerms.git
synced 2024-12-28 20:17:55 +01:00
Fully implement new SQL schema & add migration code
This commit is contained in:
parent
773bfe1407
commit
960c2291b6
@ -173,6 +173,10 @@ data:
|
||||
password: ''
|
||||
pool-size: 10 # The size of the MySQL connection pool.
|
||||
|
||||
# The prefix for all LuckPerms tables. Change this is you want to use different tables for different servers.
|
||||
# This should *not* be set to "lp_" if you have previously ran LuckPerms v2.16.81 or earlier with this database.
|
||||
table_prefix: 'luckperms_'
|
||||
|
||||
# Set to -1 to disable. If this is the only instance accessing the datastore, you can disable syncing.
|
||||
# e.g. if you're using sqlite or flatfile, this can be set to -1 to save resources.
|
||||
sync-minutes: 3
|
||||
|
@ -115,6 +115,10 @@ data:
|
||||
password: ''
|
||||
pool-size: 10 # The size of the MySQL connection pool.
|
||||
|
||||
# The prefix for all LuckPerms tables. Change this is you want to use different tables for different servers.
|
||||
# This should *not* be set to "lp_" if you have previously ran LuckPerms v2.16.81 or earlier with this database.
|
||||
table_prefix: 'luckperms_'
|
||||
|
||||
# Set to -1 to disable. If this is the only instance accessing the datastore, you can disable syncing.
|
||||
# e.g. if you're using sqlite or flatfile, this can be set to -1 to save resources.
|
||||
sync-minutes: 3
|
||||
|
@ -79,6 +79,7 @@ public abstract class AbstractConfiguration<T extends LuckPermsPlugin> implement
|
||||
private Map<String, String> groupNameRewrites;
|
||||
private List<Rule> defaultAssignments;
|
||||
private DatastoreConfiguration databaseValues;
|
||||
private String sqlTablePrefix;
|
||||
private String storageMethod;
|
||||
private boolean splitStorage;
|
||||
private Map<String, String> splitStorageOptions;
|
||||
@ -163,6 +164,7 @@ public abstract class AbstractConfiguration<T extends LuckPermsPlugin> implement
|
||||
getString("data.password", null),
|
||||
getInt("data.pool-size", 10)
|
||||
);
|
||||
sqlTablePrefix = getString("data.table_prefix", "luckperms_");
|
||||
storageMethod = getString("storage-method", defaultStorage);
|
||||
splitStorage = getBoolean("split-storage.enabled", false);
|
||||
splitStorageOptions = ImmutableMap.<String, String>builder()
|
||||
|
@ -98,6 +98,8 @@ public interface LPConfiguration {
|
||||
|
||||
DatastoreConfiguration getDatabaseValues();
|
||||
|
||||
String getSqlTablePrefix();
|
||||
|
||||
String getStorageMethod();
|
||||
|
||||
boolean isSplitStorage();
|
||||
|
@ -30,10 +30,11 @@ import me.lucko.luckperms.common.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.storage.backing.AbstractBacking;
|
||||
import me.lucko.luckperms.common.storage.backing.JSONBacking;
|
||||
import me.lucko.luckperms.common.storage.backing.MongoDBBacking;
|
||||
import me.lucko.luckperms.common.storage.backing.SQLLegacyBacking;
|
||||
import me.lucko.luckperms.common.storage.backing.SQLBacking;
|
||||
import me.lucko.luckperms.common.storage.backing.YAMLBacking;
|
||||
import me.lucko.luckperms.common.storage.backing.sqlprovider.H2Provider;
|
||||
import me.lucko.luckperms.common.storage.backing.sqlprovider.MySQLProvider;
|
||||
import me.lucko.luckperms.common.storage.backing.sqlprovider.PostgreSQLProvider;
|
||||
import me.lucko.luckperms.common.storage.backing.sqlprovider.SQLiteProvider;
|
||||
import me.lucko.luckperms.common.utils.ImmutableCollectors;
|
||||
|
||||
@ -120,11 +121,13 @@ public class StorageFactory {
|
||||
private static AbstractBacking makeBacking(StorageType method, LuckPermsPlugin plugin) {
|
||||
switch (method) {
|
||||
case MYSQL:
|
||||
return new SQLLegacyBacking(plugin, new MySQLProvider(plugin.getConfiguration().getDatabaseValues()));
|
||||
return new SQLBacking(plugin, new MySQLProvider(plugin.getConfiguration().getDatabaseValues()), plugin.getConfiguration().getSqlTablePrefix());
|
||||
case SQLITE:
|
||||
return new SQLLegacyBacking(plugin, new SQLiteProvider(new File(plugin.getDataFolder(), "luckperms.sqlite")));
|
||||
return new SQLBacking(plugin, new SQLiteProvider(new File(plugin.getDataFolder(), "luckperms.sqlite")), plugin.getConfiguration().getSqlTablePrefix());
|
||||
case H2:
|
||||
return new SQLLegacyBacking(plugin, new H2Provider(new File(plugin.getDataFolder(), "luckperms.db")));
|
||||
return new SQLBacking(plugin, new H2Provider(new File(plugin.getDataFolder(), "luckperms.db")), plugin.getConfiguration().getSqlTablePrefix());
|
||||
case POSTGRESQL:
|
||||
return new SQLBacking(plugin, new PostgreSQLProvider(plugin.getConfiguration().getDatabaseValues()), plugin.getConfiguration().getSqlTablePrefix());
|
||||
case MONGODB:
|
||||
return new MongoDBBacking(plugin, plugin.getConfiguration().getDatabaseValues());
|
||||
case YAML:
|
||||
|
@ -130,7 +130,7 @@ public class JSONBacking extends FlatfileBacking {
|
||||
if (user.getName() == null || user.getName().equalsIgnoreCase("null")) {
|
||||
user.setName(name1);
|
||||
} else {
|
||||
if (!name1.equals(user.getName())) {
|
||||
if (!name1.equalsIgnoreCase(user.getName())) {
|
||||
save = true;
|
||||
}
|
||||
}
|
||||
|
@ -235,7 +235,7 @@ public class MongoDBBacking extends AbstractBacking {
|
||||
if (user.getName() == null || user.getName().equalsIgnoreCase("null")) {
|
||||
user.setName(d.getString("name"));
|
||||
} else {
|
||||
if (!d.getString("name").equals(user.getName())) {
|
||||
if (!d.getString("name").equalsIgnoreCase(user.getName())) {
|
||||
save = true;
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,8 @@
|
||||
|
||||
package me.lucko.luckperms.common.storage.backing;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
@ -38,6 +40,7 @@ import me.lucko.luckperms.common.managers.GroupManager;
|
||||
import me.lucko.luckperms.common.managers.TrackManager;
|
||||
import me.lucko.luckperms.common.managers.impl.GenericUserManager;
|
||||
import me.lucko.luckperms.common.storage.backing.sqlprovider.SQLProvider;
|
||||
import me.lucko.luckperms.common.storage.backing.utils.LegacySchemaMigration;
|
||||
import me.lucko.luckperms.common.storage.backing.utils.NodeDataHolder;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
@ -65,7 +68,7 @@ public class SQLBacking extends AbstractBacking {
|
||||
private static final Type LIST_STRING_TYPE = new TypeToken<List<String>>(){}.getType();
|
||||
|
||||
private static final String USER_PERMISSIONS_SELECT = "SELECT permission, value, server, world, expiry, contexts FROM {prefix}user_permissions WHERE uuid=?";
|
||||
private static final String USER_PERMISSIONS_DELETE_SPECIFIC = "DELETE FROM {prefix}user_permissions WHERE uuid=?, permission=?, value=?, server=?, world=?, expiry=?, contexts=?";
|
||||
private static final String USER_PERMISSIONS_DELETE_SPECIFIC = "DELETE FROM {prefix}user_permissions WHERE uuid=? AND permission=? AND value=? AND server=? AND world=? AND expiry=? AND contexts=?";
|
||||
private static final String USER_PERMISSIONS_DELETE = "DELETE FROM {prefix}user_permissions WHERE uuid=?";
|
||||
private static final String USER_PERMISSIONS_INSERT = "INSERT INTO {prefix}user_permissions(uuid, permission, value, server, world, expiry, contexts) VALUES(?, ?, ?, ?, ?, ?, ?)";
|
||||
private static final String USER_PERMISSIONS_SELECT_DISTINCT = "SELECT DISTINCT uuid FROM {prefix}user_permissions";
|
||||
@ -76,10 +79,11 @@ public class SQLBacking extends AbstractBacking {
|
||||
private static final String PLAYER_INSERT = "INSERT INTO {prefix}players VALUES(?, ?, ?)";
|
||||
private static final String PLAYER_UPDATE = "UPDATE {prefix}players SET username=? WHERE uuid=?";
|
||||
private static final String PLAYER_UPDATE_FULL = "UPDATE {prefix}players SET username=?, primary_group=? WHERE uuid=?";
|
||||
private static final String PLAYER_UPDATE_PRIMARY_GROUP = "UPDATE {prefix}players SET primary_group=? WHERE uuid=?";
|
||||
|
||||
private static final String GROUP_PERMISSIONS_SELECT = "SELECT permission, value, server, world, expiry, contexts FROM {prefix}group_permissions WHERE name=?";
|
||||
private static final String GROUP_PERMISSIONS_DELETE = "DELETE FROM {prefix}group_permissions WHERE name=?";
|
||||
private static final String GROUP_PERMISSIONS_DELETE_SPECIFIC = "DELETE FROM {prefix}group_permissions WHERE name=?, permission=?, value=?, server=?, world=?, expiry=?, contexts=?";
|
||||
private static final String GROUP_PERMISSIONS_DELETE_SPECIFIC = "DELETE FROM {prefix}group_permissions WHERE name=? AND permission=? AND value=? AND server=? AND world=? AND expiry=? AND contexts=?";
|
||||
private static final String GROUP_PERMISSIONS_INSERT = "INSERT INTO {prefix}group_permissions(name, permission, value, server, world, expiry, contexts) VALUES(?, ?, ?, ?, ?, ?, ?)";
|
||||
|
||||
private static final String GROUP_SELECT_ALL = "SELECT name FROM {prefix}groups";
|
||||
@ -96,8 +100,12 @@ public class SQLBacking extends AbstractBacking {
|
||||
private static final String ACTION_SELECT_ALL = "SELECT * FROM {prefix}actions";
|
||||
|
||||
|
||||
@Getter
|
||||
private final Gson gson;
|
||||
|
||||
@Getter
|
||||
private final SQLProvider provider;
|
||||
@Getter
|
||||
private final Function<String, String> prefix;
|
||||
|
||||
public SQLBacking(LuckPermsPlugin plugin, SQLProvider provider, String prefix) {
|
||||
@ -109,7 +117,14 @@ public class SQLBacking extends AbstractBacking {
|
||||
|
||||
private boolean tableExists(String table) throws SQLException {
|
||||
try (Connection connection = provider.getConnection()) {
|
||||
return connection.getMetaData().getTables(null, null, table.toUpperCase(), null).next();
|
||||
try (ResultSet rs = connection.getMetaData().getTables(null, null, "%", null)) {
|
||||
while (rs.next()) {
|
||||
if (rs.getString(3).equalsIgnoreCase(table)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -152,6 +167,15 @@ public class SQLBacking extends AbstractBacking {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Try migration from legacy backing
|
||||
if (tableExists("lp_users")) {
|
||||
plugin.getLog().severe("===== Legacy Schema Migration =====");
|
||||
plugin.getLog().severe("Starting migration from legacy schema. This could take a while....");
|
||||
plugin.getLog().severe("Please do not stop your server while the migration takes place.");
|
||||
|
||||
new LegacySchemaMigration(this).run();
|
||||
}
|
||||
}
|
||||
|
||||
setAcceptingLogins(true);
|
||||
@ -289,7 +313,7 @@ public class SQLBacking extends AbstractBacking {
|
||||
user.setName(name);
|
||||
} else {
|
||||
// The name in storage is not the same as their actual name.
|
||||
if (!name.equals(user.getName())) {
|
||||
if (!name.equalsIgnoreCase(user.getName())) {
|
||||
save = true;
|
||||
}
|
||||
}
|
||||
@ -327,6 +351,11 @@ public class SQLBacking extends AbstractBacking {
|
||||
ps.setString(1, user.getUuid().toString());
|
||||
ps.execute();
|
||||
}
|
||||
try (PreparedStatement ps = c.prepareStatement(prefix.apply(PLAYER_UPDATE_PRIMARY_GROUP))) {
|
||||
ps.setString(1, "default");
|
||||
ps.setString(2, user.getUuid().toString());
|
||||
ps.execute();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
|
@ -1,685 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.storage.backing;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import me.lucko.luckperms.api.LogEntry;
|
||||
import me.lucko.luckperms.common.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.core.UserIdentifier;
|
||||
import me.lucko.luckperms.common.core.model.Group;
|
||||
import me.lucko.luckperms.common.core.model.Track;
|
||||
import me.lucko.luckperms.common.core.model.User;
|
||||
import me.lucko.luckperms.common.data.Log;
|
||||
import me.lucko.luckperms.common.managers.GroupManager;
|
||||
import me.lucko.luckperms.common.managers.TrackManager;
|
||||
import me.lucko.luckperms.common.managers.impl.GenericUserManager;
|
||||
import me.lucko.luckperms.common.storage.backing.sqlprovider.H2Provider;
|
||||
import me.lucko.luckperms.common.storage.backing.sqlprovider.MySQLProvider;
|
||||
import me.lucko.luckperms.common.storage.backing.sqlprovider.SQLProvider;
|
||||
import me.lucko.luckperms.common.storage.backing.sqlprovider.SQLiteProvider;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import static me.lucko.luckperms.common.core.model.PermissionHolder.exportToLegacy;
|
||||
import static me.lucko.luckperms.common.storage.backing.sqlprovider.SQLProvider.QueryPS;
|
||||
import static me.lucko.luckperms.common.storage.backing.sqlprovider.SQLProvider.QueryRS;
|
||||
|
||||
public class SQLLegacyBacking extends AbstractBacking {
|
||||
private static final Type NM_TYPE = new TypeToken<Map<String, Boolean>>() {}.getType();
|
||||
private static final Type T_TYPE = new TypeToken<List<String>>() {}.getType();
|
||||
|
||||
private static final String MYSQL_CREATETABLE_UUID = "CREATE TABLE IF NOT EXISTS `lp_uuid` (`name` VARCHAR(16) NOT NULL, `uuid` VARCHAR(36) NOT NULL, PRIMARY KEY (`name`)) DEFAULT CHARSET=utf8;";
|
||||
private static final String MYSQL_CREATETABLE_USERS = "CREATE TABLE IF NOT EXISTS `lp_users` (`uuid` VARCHAR(36) NOT NULL, `name` VARCHAR(16) NOT NULL, `primary_group` VARCHAR(36) NOT NULL, `perms` TEXT NOT NULL, PRIMARY KEY (`uuid`)) DEFAULT CHARSET=utf8;";
|
||||
private static final String MYSQL_CREATETABLE_GROUPS = "CREATE TABLE IF NOT EXISTS `lp_groups` (`name` VARCHAR(36) NOT NULL, `perms` TEXT NULL, PRIMARY KEY (`name`)) DEFAULT CHARSET=utf8;";
|
||||
private static final String MYSQL_CREATETABLE_TRACKS = "CREATE TABLE IF NOT EXISTS `lp_tracks` (`name` VARCHAR(36) NOT NULL, `groups` TEXT NULL, PRIMARY KEY (`name`)) DEFAULT CHARSET=utf8;";
|
||||
private static final String MYSQL_CREATETABLE_ACTION = "CREATE TABLE IF NOT EXISTS `lp_actions` (`id` INT AUTO_INCREMENT NOT NULL, `time` BIGINT NOT NULL, `actor_uuid` VARCHAR(36) NOT NULL, `actor_name` VARCHAR(16) NOT NULL, `type` CHAR(1) NOT NULL, `acted_uuid` VARCHAR(36) NOT NULL, `acted_name` VARCHAR(36) NOT NULL, `action` VARCHAR(256) NOT NULL, PRIMARY KEY (`id`)) DEFAULT CHARSET=utf8;";
|
||||
|
||||
private static final String H2_CREATETABLE_UUID = "CREATE TABLE IF NOT EXISTS `lp_uuid` (`name` VARCHAR(16) NOT NULL, `uuid` VARCHAR(36) NOT NULL, PRIMARY KEY (`name`)) DEFAULT CHARSET=utf8;";
|
||||
private static final String H2_CREATETABLE_USERS = "CREATE TABLE IF NOT EXISTS `lp_users` (`uuid` VARCHAR(36) NOT NULL, `name` VARCHAR(16) NOT NULL, `primary_group` VARCHAR(36) NOT NULL, `perms` TEXT NOT NULL, PRIMARY KEY (`uuid`)) DEFAULT CHARSET=utf8;";
|
||||
private static final String H2_CREATETABLE_GROUPS = "CREATE TABLE IF NOT EXISTS `lp_groups` (`name` VARCHAR(36) NOT NULL, `perms` TEXT NULL, PRIMARY KEY (`name`)) DEFAULT CHARSET=utf8;";
|
||||
private static final String H2_CREATETABLE_TRACKS = "CREATE TABLE IF NOT EXISTS `lp_tracks` (`name` VARCHAR(36) NOT NULL, `groups` TEXT NULL, PRIMARY KEY (`name`)) DEFAULT CHARSET=utf8;";
|
||||
private static final String H2_CREATETABLE_ACTION = "CREATE TABLE IF NOT EXISTS `lp_actions` (`id` INT AUTO_INCREMENT NOT NULL, `time` BIGINT NOT NULL, `actor_uuid` VARCHAR(36) NOT NULL, `actor_name` VARCHAR(16) NOT NULL, `type` CHAR(1) NOT NULL, `acted_uuid` VARCHAR(36) NOT NULL, `acted_name` VARCHAR(36) NOT NULL, `action` VARCHAR(256) NOT NULL, PRIMARY KEY (`id`)) DEFAULT CHARSET=utf8;";
|
||||
|
||||
private static final String SQLITE_CREATETABLE_UUID = "CREATE TABLE IF NOT EXISTS `lp_uuid` (`name` VARCHAR(16) NOT NULL, `uuid` VARCHAR(36) NOT NULL, PRIMARY KEY (`name`));";
|
||||
private static final String SQLITE_CREATETABLE_USERS = "CREATE TABLE IF NOT EXISTS `lp_users` (`uuid` VARCHAR(36) NOT NULL, `name` VARCHAR(16) NOT NULL, `primary_group` VARCHAR(36) NOT NULL, `perms` TEXT NOT NULL, PRIMARY KEY (`uuid`));";
|
||||
private static final String SQLITE_CREATETABLE_GROUPS = "CREATE TABLE IF NOT EXISTS `lp_groups` (`name` VARCHAR(36) NOT NULL, `perms` TEXT NULL, PRIMARY KEY (`name`));";
|
||||
private static final String SQLITE_CREATETABLE_TRACKS = "CREATE TABLE IF NOT EXISTS `lp_tracks` (`name` VARCHAR(36) NOT NULL, `groups` TEXT NULL, PRIMARY KEY (`name`));";
|
||||
private static final String SQLITE_CREATETABLE_ACTION = "CREATE TABLE IF NOT EXISTS `lp_actions` (`id` INTEGER PRIMARY KEY NOT NULL, `time` BIG INT NOT NULL, `actor_uuid` VARCHAR(36) NOT NULL, `actor_name` VARCHAR(16) NOT NULL, `type` CHAR(1) NOT NULL, `acted_uuid` VARCHAR(36) NOT NULL, `acted_name` VARCHAR(36) NOT NULL, `action` VARCHAR(256) NOT NULL);";
|
||||
|
||||
private static final Map<Class<? extends SQLProvider>, String[]> INIT_QUERIES = ImmutableMap.<Class<? extends SQLProvider>, String[]>builder()
|
||||
.put(MySQLProvider.class, new String[]{MYSQL_CREATETABLE_UUID, MYSQL_CREATETABLE_USERS, MYSQL_CREATETABLE_GROUPS, MYSQL_CREATETABLE_TRACKS, MYSQL_CREATETABLE_ACTION})
|
||||
.put(H2Provider.class, new String[]{H2_CREATETABLE_UUID, H2_CREATETABLE_USERS, H2_CREATETABLE_GROUPS, H2_CREATETABLE_TRACKS, H2_CREATETABLE_ACTION})
|
||||
.put(SQLiteProvider.class, new String[]{SQLITE_CREATETABLE_UUID, SQLITE_CREATETABLE_USERS, SQLITE_CREATETABLE_GROUPS, SQLITE_CREATETABLE_TRACKS, SQLITE_CREATETABLE_ACTION})
|
||||
.build();
|
||||
|
||||
private static final String USER_INSERT = "INSERT INTO lp_users VALUES(?, ?, ?, ?)";
|
||||
private static final String USER_SELECT = "SELECT * FROM lp_users WHERE uuid=?";
|
||||
private static final String USER_SELECT_ALL = "SELECT uuid FROM lp_users";
|
||||
private static final String USER_UPDATE = "UPDATE lp_users SET name=?, primary_group = ?, perms=? WHERE uuid=?";
|
||||
private static final String USER_DELETE = "DELETE FROM lp_users WHERE uuid=?";
|
||||
private static final String USER_DELETE_ALL = "DELETE FROM lp_users WHERE perms=?";
|
||||
|
||||
private static final String GROUP_INSERT = "INSERT INTO lp_groups VALUES(?, ?)";
|
||||
private static final String GROUP_SELECT = "SELECT perms FROM lp_groups WHERE name=?";
|
||||
private static final String GROUP_SELECT_ALL = "SELECT * FROM lp_groups";
|
||||
private static final String GROUP_UPDATE = "UPDATE lp_groups SET perms=? WHERE name=?";
|
||||
private static final String GROUP_DELETE = "DELETE FROM lp_groups WHERE name=?";
|
||||
|
||||
private static final String TRACK_INSERT = "INSERT INTO lp_tracks VALUES(?, ?)";
|
||||
private static final String TRACK_SELECT = "SELECT groups FROM lp_tracks WHERE name=?";
|
||||
private static final String TRACK_SELECT_ALL = "SELECT * FROM lp_tracks";
|
||||
private static final String TRACK_UPDATE = "UPDATE lp_tracks SET groups=? WHERE name=?";
|
||||
private static final String TRACK_DELETE = "DELETE FROM lp_tracks WHERE name=?";
|
||||
|
||||
private static final String UUIDCACHE_INSERT = "INSERT INTO lp_uuid VALUES(?, ?)";
|
||||
private static final String UUIDCACHE_SELECT = "SELECT uuid FROM lp_uuid WHERE name=?";
|
||||
private static final String UUIDCACHE_SELECT_NAME = "SELECT name FROM lp_uuid WHERE uuid=?";
|
||||
private static final String UUIDCACHE_UPDATE = "UPDATE lp_uuid SET uuid=? WHERE name=?";
|
||||
|
||||
private static final String ACTION_INSERT = "INSERT INTO lp_actions(`time`, `actor_uuid`, `actor_name`, `type`, `acted_uuid`, `acted_name`, `action`) VALUES(?, ?, ?, ?, ?, ?, ?)";
|
||||
private static final String ACTION_SELECT_ALL = "SELECT * FROM lp_actions";
|
||||
|
||||
private final Gson gson;
|
||||
private final SQLProvider provider;
|
||||
|
||||
public SQLLegacyBacking(LuckPermsPlugin plugin, SQLProvider provider) {
|
||||
super(plugin, provider.getName());
|
||||
this.provider = provider;
|
||||
gson = new Gson();
|
||||
}
|
||||
|
||||
private boolean runQuery(String query, QueryPS queryPS) {
|
||||
return provider.runQuery(query, queryPS);
|
||||
}
|
||||
|
||||
private boolean runQuery(String query, QueryPS queryPS, QueryRS queryRS) {
|
||||
return provider.runQuery(query, queryPS, queryRS);
|
||||
}
|
||||
|
||||
private boolean runQuery(String query) {
|
||||
return provider.runQuery(query);
|
||||
}
|
||||
|
||||
private boolean runQuery(String query, QueryRS queryRS) {
|
||||
return provider.runQuery(query, queryRS);
|
||||
}
|
||||
|
||||
private boolean setupTables(String[] tableQueries) {
|
||||
boolean success = true;
|
||||
for (String q : tableQueries) {
|
||||
if (!runQuery(q)) success = false;
|
||||
}
|
||||
|
||||
return success && cleanupUsers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
try {
|
||||
provider.init();
|
||||
|
||||
if (!setupTables(INIT_QUERIES.get(provider.getClass()))) {
|
||||
plugin.getLog().severe("Error occurred whilst initialising the database.");
|
||||
shutdown();
|
||||
} else {
|
||||
setAcceptingLogins(true);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
try {
|
||||
provider.shutdown();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean logAction(LogEntry entry) {
|
||||
return runQuery(ACTION_INSERT, preparedStatement -> {
|
||||
preparedStatement.setLong(1, entry.getTimestamp());
|
||||
preparedStatement.setString(2, entry.getActor().toString());
|
||||
preparedStatement.setString(3, entry.getActorName());
|
||||
preparedStatement.setString(4, Character.toString(entry.getType()));
|
||||
preparedStatement.setString(5, entry.getActed() == null ? "null" : entry.getActed().toString());
|
||||
preparedStatement.setString(6, entry.getActedName());
|
||||
preparedStatement.setString(7, entry.getAction());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Log getLog() {
|
||||
final Log.Builder log = Log.builder();
|
||||
boolean success = runQuery(ACTION_SELECT_ALL, resultSet -> {
|
||||
while (resultSet.next()) {
|
||||
final String actedUuid = resultSet.getString("acted_uuid");
|
||||
LogEntry e = new LogEntry(
|
||||
resultSet.getLong("time"),
|
||||
UUID.fromString(resultSet.getString("actor_uuid")),
|
||||
resultSet.getString("actor_name"),
|
||||
resultSet.getString("type").toCharArray()[0],
|
||||
actedUuid.equals("null") ? null : UUID.fromString(actedUuid),
|
||||
resultSet.getString("acted_name"),
|
||||
resultSet.getString("action")
|
||||
);
|
||||
log.add(e);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return success ? log.build() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean loadUser(UUID uuid, String username) {
|
||||
User user = plugin.getUserManager().getOrMake(UserIdentifier.of(uuid, username));
|
||||
user.getIoLock().lock();
|
||||
try {
|
||||
// screw "effectively final"
|
||||
final String[] perms = new String[1];
|
||||
final String[] pg = new String[1];
|
||||
final String[] name = new String[1];
|
||||
final boolean[] exists = {false};
|
||||
|
||||
boolean s = runQuery(USER_SELECT,
|
||||
preparedStatement -> preparedStatement.setString(1, user.getUuid().toString()),
|
||||
resultSet -> {
|
||||
if (resultSet.next()) {
|
||||
// User exists.
|
||||
exists[0] = true;
|
||||
perms[0] = resultSet.getString("perms");
|
||||
pg[0] = resultSet.getString("primary_group");
|
||||
name[0] = resultSet.getString("name");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
if (!s) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (exists[0]) {
|
||||
// User exists, let's load.
|
||||
Map<String, Boolean> nodes = gson.fromJson(perms[0], NM_TYPE);
|
||||
|
||||
user.setNodes(nodes);
|
||||
user.setPrimaryGroup(pg[0]);
|
||||
|
||||
boolean save = plugin.getUserManager().giveDefaultIfNeeded(user, false);
|
||||
|
||||
if (user.getName() == null || user.getName().equalsIgnoreCase("null")) {
|
||||
user.setName(name[0]);
|
||||
} else {
|
||||
if (!name[0].equals(user.getName())) {
|
||||
save = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (save) {
|
||||
String json = gson.toJson(exportToLegacy(user.getNodes()));
|
||||
runQuery(USER_UPDATE, preparedStatement -> {
|
||||
preparedStatement.setString(1, user.getName());
|
||||
preparedStatement.setString(2, user.getPrimaryGroup());
|
||||
preparedStatement.setString(3, json);
|
||||
preparedStatement.setString(4, user.getUuid().toString());
|
||||
});
|
||||
}
|
||||
|
||||
} else {
|
||||
if (GenericUserManager.shouldSave(user)) {
|
||||
user.clearNodes();
|
||||
user.setPrimaryGroup(null);
|
||||
plugin.getUserManager().giveDefaultIfNeeded(user, false);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
} finally {
|
||||
user.getIoLock().unlock();
|
||||
user.getRefreshBuffer().requestDirectly();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean saveUser(User user) {
|
||||
if (!GenericUserManager.shouldSave(user)) {
|
||||
user.getIoLock().lock();
|
||||
try {
|
||||
return runQuery(USER_DELETE, preparedStatement -> {
|
||||
preparedStatement.setString(1, user.getUuid().toString());
|
||||
});
|
||||
} finally {
|
||||
user.getIoLock().unlock();
|
||||
}
|
||||
// return true above ^^^^^
|
||||
}
|
||||
|
||||
user.getIoLock().lock();
|
||||
try {
|
||||
final boolean[] exists = {false};
|
||||
boolean success = runQuery(USER_SELECT,
|
||||
preparedStatement -> preparedStatement.setString(1, user.getUuid().toString()),
|
||||
resultSet -> {
|
||||
if (resultSet.next()) {
|
||||
exists[0] = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
if (!success) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final String s = gson.toJson(exportToLegacy(user.getNodes()));
|
||||
|
||||
if (exists[0]) {
|
||||
// User exists, let's update.
|
||||
return runQuery(USER_UPDATE, preparedStatement -> {
|
||||
preparedStatement.setString(1, user.getName());
|
||||
preparedStatement.setString(2, user.getPrimaryGroup());
|
||||
preparedStatement.setString(3, s);
|
||||
preparedStatement.setString(4, user.getUuid().toString());
|
||||
});
|
||||
} else {
|
||||
// Doesn't already exist, let's insert.
|
||||
return runQuery(USER_INSERT, preparedStatement -> {
|
||||
preparedStatement.setString(1, user.getUuid().toString());
|
||||
preparedStatement.setString(2, user.getName());
|
||||
preparedStatement.setString(3, user.getPrimaryGroup());
|
||||
preparedStatement.setString(4, s);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
} finally {
|
||||
user.getIoLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cleanupUsers() {
|
||||
return runQuery(USER_DELETE_ALL, preparedStatement -> {
|
||||
preparedStatement.setString(1, "{\"group.default\":true}");
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> getUniqueUsers() {
|
||||
Set<UUID> uuids = new HashSet<>();
|
||||
|
||||
boolean success = runQuery(USER_SELECT_ALL, resultSet -> {
|
||||
while (resultSet.next()) {
|
||||
String uuid = resultSet.getString("uuid");
|
||||
uuids.add(UUID.fromString(uuid));
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
return success ? uuids : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean createAndLoadGroup(String name) {
|
||||
Group group = plugin.getGroupManager().getOrMake(name);
|
||||
group.getIoLock().lock();
|
||||
try {
|
||||
final boolean[] exists = {false};
|
||||
final String[] perms = new String[1];
|
||||
|
||||
boolean s = runQuery(GROUP_SELECT,
|
||||
preparedStatement -> preparedStatement.setString(1, group.getName()),
|
||||
resultSet -> {
|
||||
if (resultSet.next()) {
|
||||
exists[0] = true;
|
||||
perms[0] = resultSet.getString("perms");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
if (!s) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (exists[0]) {
|
||||
// Group exists, let's load.
|
||||
Map<String, Boolean> nodes = gson.fromJson(perms[0], NM_TYPE);
|
||||
group.setNodes(nodes);
|
||||
return true;
|
||||
} else {
|
||||
String json = gson.toJson(exportToLegacy(group.getNodes()));
|
||||
return runQuery(GROUP_INSERT, preparedStatement -> {
|
||||
preparedStatement.setString(1, group.getName());
|
||||
preparedStatement.setString(2, json);
|
||||
});
|
||||
}
|
||||
|
||||
} finally {
|
||||
group.getIoLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean loadGroup(String name) {
|
||||
Group group = plugin.getGroupManager().getOrMake(name);
|
||||
group.getIoLock().lock();
|
||||
try {
|
||||
final String[] perms = new String[1];
|
||||
boolean s = runQuery(GROUP_SELECT,
|
||||
preparedStatement -> preparedStatement.setString(1, name),
|
||||
resultSet -> {
|
||||
if (resultSet.next()) {
|
||||
perms[0] = resultSet.getString("perms");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
);
|
||||
|
||||
if (!s) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Group exists, let's load.
|
||||
Map<String, Boolean> nodes = gson.fromJson(perms[0], NM_TYPE);
|
||||
group.setNodes(nodes);
|
||||
return true;
|
||||
|
||||
} finally {
|
||||
group.getIoLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean loadAllGroups() {
|
||||
List<String> groups = new ArrayList<>();
|
||||
boolean b = runQuery(GROUP_SELECT_ALL, resultSet -> {
|
||||
while (resultSet.next()) {
|
||||
String name = resultSet.getString("name");
|
||||
groups.add(name);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (!b) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (String g : groups) {
|
||||
if (!loadGroup(g)) {
|
||||
b = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (b) {
|
||||
GroupManager gm = plugin.getGroupManager();
|
||||
gm.getAll().values().stream()
|
||||
.filter(g -> !groups.contains(g.getName()))
|
||||
.forEach(gm::unload);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean saveGroup(Group group) {
|
||||
group.getIoLock().lock();
|
||||
try {
|
||||
String json = gson.toJson(exportToLegacy(group.getNodes()));
|
||||
return runQuery(GROUP_UPDATE, preparedStatement -> {
|
||||
preparedStatement.setString(1, json);
|
||||
preparedStatement.setString(2, group.getName());
|
||||
});
|
||||
} finally {
|
||||
group.getIoLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteGroup(Group group) {
|
||||
group.getIoLock().lock();
|
||||
boolean success;
|
||||
try {
|
||||
success = runQuery(GROUP_DELETE, preparedStatement -> {
|
||||
preparedStatement.setString(1, group.getName());
|
||||
});
|
||||
} finally {
|
||||
group.getIoLock().unlock();
|
||||
}
|
||||
|
||||
if (success) plugin.getGroupManager().unload(group);
|
||||
return success;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean createAndLoadTrack(String name) {
|
||||
Track track = plugin.getTrackManager().getOrMake(name);
|
||||
track.getIoLock().lock();
|
||||
try {
|
||||
final boolean[] exists = {false};
|
||||
final String[] groups = new String[1];
|
||||
|
||||
boolean s = runQuery(TRACK_SELECT,
|
||||
preparedStatement -> preparedStatement.setString(1, track.getName()),
|
||||
resultSet -> {
|
||||
if (resultSet.next()) {
|
||||
exists[0] = true;
|
||||
groups[0] = resultSet.getString("groups");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
if (!s) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (exists[0]) {
|
||||
// Track exists, let's load.
|
||||
track.setGroups(gson.fromJson(groups[0], T_TYPE));
|
||||
return true;
|
||||
} else {
|
||||
String json = gson.toJson(track.getGroups());
|
||||
return runQuery(TRACK_INSERT, preparedStatement -> {
|
||||
preparedStatement.setString(1, track.getName());
|
||||
preparedStatement.setString(2, json);
|
||||
});
|
||||
}
|
||||
|
||||
} finally {
|
||||
track.getIoLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean loadTrack(String name) {
|
||||
Track track = plugin.getTrackManager().getOrMake(name);
|
||||
track.getIoLock().lock();
|
||||
try {
|
||||
final String[] groups = {null};
|
||||
boolean s = runQuery(TRACK_SELECT,
|
||||
preparedStatement -> preparedStatement.setString(1, name),
|
||||
resultSet -> {
|
||||
if (resultSet.next()) {
|
||||
groups[0] = resultSet.getString("groups");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
);
|
||||
|
||||
if (!s) {
|
||||
return false;
|
||||
}
|
||||
|
||||
track.setGroups(gson.fromJson(groups[0], T_TYPE));
|
||||
return true;
|
||||
|
||||
} finally {
|
||||
track.getIoLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean loadAllTracks() {
|
||||
List<String> tracks = new ArrayList<>();
|
||||
boolean b = runQuery(TRACK_SELECT_ALL, resultSet -> {
|
||||
while (resultSet.next()) {
|
||||
String name = resultSet.getString("name");
|
||||
tracks.add(name);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (!b) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (String t : tracks) {
|
||||
if (!loadTrack(t)) {
|
||||
b = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (b) {
|
||||
TrackManager tm = plugin.getTrackManager();
|
||||
tm.getAll().values().stream()
|
||||
.filter(t -> !tracks.contains(t.getName()))
|
||||
.forEach(tm::unload);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean saveTrack(Track track) {
|
||||
track.getIoLock().lock();
|
||||
try {
|
||||
String s = gson.toJson(track.getGroups());
|
||||
return runQuery(TRACK_UPDATE, preparedStatement -> {
|
||||
preparedStatement.setString(1, s);
|
||||
preparedStatement.setString(2, track.getName());
|
||||
});
|
||||
} finally {
|
||||
track.getIoLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteTrack(Track track) {
|
||||
track.getIoLock().lock();
|
||||
boolean success;
|
||||
try {
|
||||
success = runQuery(TRACK_DELETE, preparedStatement -> {
|
||||
preparedStatement.setString(1, track.getName());
|
||||
});
|
||||
} finally {
|
||||
track.getIoLock().unlock();
|
||||
}
|
||||
|
||||
if (success) plugin.getTrackManager().unload(track);
|
||||
return success;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean saveUUIDData(String username, UUID uuid) {
|
||||
final String u = username.toLowerCase();
|
||||
final boolean[] update = {false};
|
||||
boolean s = runQuery(UUIDCACHE_SELECT,
|
||||
preparedStatement -> preparedStatement.setString(1, u),
|
||||
resultSet -> {
|
||||
if (resultSet.next()) {
|
||||
update[0] = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
if (!s) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (update[0]) {
|
||||
return runQuery(UUIDCACHE_UPDATE, preparedStatement -> {
|
||||
preparedStatement.setString(1, uuid.toString());
|
||||
preparedStatement.setString(2, u);
|
||||
});
|
||||
} else {
|
||||
return runQuery(UUIDCACHE_INSERT, preparedStatement -> {
|
||||
preparedStatement.setString(1, u);
|
||||
preparedStatement.setString(2, uuid.toString());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getUUID(String username) {
|
||||
final String u = username.toLowerCase();
|
||||
final UUID[] uuid = {null};
|
||||
|
||||
boolean success = runQuery(UUIDCACHE_SELECT,
|
||||
preparedStatement -> preparedStatement.setString(1, u),
|
||||
resultSet -> {
|
||||
if (resultSet.next()) {
|
||||
uuid[0] = UUID.fromString(resultSet.getString("uuid"));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
);
|
||||
|
||||
return success ? uuid[0] : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName(UUID uuid) {
|
||||
final String u = uuid.toString();
|
||||
final String[] name = {null};
|
||||
|
||||
boolean success = runQuery(UUIDCACHE_SELECT_NAME,
|
||||
preparedStatement -> preparedStatement.setString(1, u),
|
||||
resultSet -> {
|
||||
if (resultSet.next()) {
|
||||
name[0] = resultSet.getString("name");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
);
|
||||
|
||||
return success ? name[0] : null;
|
||||
}
|
||||
}
|
@ -119,7 +119,7 @@ public class YAMLBacking extends FlatfileBacking {
|
||||
if (user.getName() == null || user.getName().equalsIgnoreCase("null")) {
|
||||
user.setName(name);
|
||||
} else {
|
||||
if (!name.equals(user.getName())) {
|
||||
if (!name.equalsIgnoreCase(user.getName())) {
|
||||
save = true;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,277 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.storage.backing.utils;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import me.lucko.luckperms.common.core.NodeFactory;
|
||||
import me.lucko.luckperms.common.storage.backing.SQLBacking;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class LegacySchemaMigration implements Runnable {
|
||||
private static final Type NODE_MAP_TYPE = new TypeToken<Map<String, Boolean>>() {}.getType();
|
||||
private final SQLBacking backing;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
backing.getPlugin().getLog().info("Collecting UUID data from the old tables.");
|
||||
|
||||
Map<UUID, String> uuidData = new HashMap<>();
|
||||
try (Connection c = backing.getProvider().getConnection()) {
|
||||
try (PreparedStatement ps = c.prepareStatement("SELECT uuid, name FROM lp_uuid")) {
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
while (rs.next()) {
|
||||
try {
|
||||
uuidData.put(UUID.fromString(rs.getString("uuid")), rs.getString("name"));
|
||||
} catch (IllegalArgumentException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
backing.getPlugin().getLog().info("Found " + uuidData.size() + " uuid data entries. Copying to new tables...");
|
||||
|
||||
List<Map.Entry<UUID, String>> uuidEntries = uuidData.entrySet().stream().collect(Collectors.toList());
|
||||
List<List<Map.Entry<UUID, String>>> partitionedUuidEntries = Lists.partition(uuidEntries, 100);
|
||||
|
||||
for (List<Map.Entry<UUID, String>> l : partitionedUuidEntries) {
|
||||
try (Connection c = backing.getProvider().getConnection()) {
|
||||
try (PreparedStatement ps = c.prepareStatement(backing.getPrefix().apply("INSERT INTO {prefix}players VALUES(?, ?, ?)"))) {
|
||||
for (Map.Entry<UUID, String> e : l) {
|
||||
ps.setString(1, e.getKey().toString());
|
||||
ps.setString(2, e.getValue().toLowerCase());
|
||||
ps.setString(3, "default");
|
||||
ps.addBatch();
|
||||
}
|
||||
ps.executeBatch();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
uuidData.clear();
|
||||
uuidEntries.clear();
|
||||
partitionedUuidEntries.clear();
|
||||
|
||||
backing.getPlugin().getLog().info("Migrated all uuid data.");
|
||||
backing.getPlugin().getLog().info("Starting user data migration.");
|
||||
|
||||
Set<UUID> users = new HashSet<>();
|
||||
try (Connection c = backing.getProvider().getConnection()) {
|
||||
try (PreparedStatement ps = c.prepareStatement("SELECT uuid FROM lp_users")) {
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
while (rs.next()) {
|
||||
try {
|
||||
users.add(UUID.fromString(rs.getString("uuid")));
|
||||
} catch (IllegalArgumentException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
backing.getPlugin().getLog().info("Found " + users.size() + " user data entries. Copying to new tables...");
|
||||
|
||||
AtomicInteger userCounter = new AtomicInteger(0);
|
||||
for (UUID uuid : users) {
|
||||
String permsJson = null;
|
||||
String primaryGroup = null;
|
||||
|
||||
try (Connection c = backing.getProvider().getConnection()) {
|
||||
try (PreparedStatement ps = c.prepareStatement("SELECT primary_group, perms FROM lp_users WHERE uuid=?")) {
|
||||
ps.setString(1, uuid.toString());
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
if (rs.next()) {
|
||||
permsJson = rs.getString("perms");
|
||||
primaryGroup = rs.getString("primary_group");
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (permsJson == null || primaryGroup == null) {
|
||||
new Throwable().printStackTrace();
|
||||
continue;
|
||||
}
|
||||
|
||||
Map<String, Boolean> convertedPerms = backing.getGson().fromJson(permsJson, NODE_MAP_TYPE);
|
||||
if (convertedPerms == null) {
|
||||
new Throwable().printStackTrace();
|
||||
continue;
|
||||
}
|
||||
|
||||
Set<NodeDataHolder> nodes = convertedPerms.entrySet().stream()
|
||||
.map(e -> NodeFactory.fromSerialisedNode(e.getKey(), e.getValue()))
|
||||
.map(NodeDataHolder::fromNode)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
try (Connection c = backing.getProvider().getConnection()) {
|
||||
try (PreparedStatement ps = c.prepareStatement(backing.getPrefix().apply("INSERT INTO {prefix}user_permissions(uuid, permission, value, server, world, expiry, contexts) VALUES(?, ?, ?, ?, ?, ?, ?)"))) {
|
||||
for (NodeDataHolder nd : nodes) {
|
||||
ps.setString(1, uuid.toString());
|
||||
ps.setString(2, nd.getPermission());
|
||||
ps.setBoolean(3, nd.isValue());
|
||||
ps.setString(4, nd.getServer());
|
||||
ps.setString(5, nd.getWorld());
|
||||
ps.setLong(6, nd.getExpiry());
|
||||
ps.setString(7, nd.getContexts());
|
||||
ps.addBatch();
|
||||
}
|
||||
ps.executeBatch();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (!primaryGroup.equalsIgnoreCase("default")) {
|
||||
try (Connection c = backing.getProvider().getConnection()) {
|
||||
try (PreparedStatement ps = c.prepareStatement(backing.getPrefix().apply("UPDATE {prefix}players SET primary_group=? WHERE uuid=?"))) {
|
||||
ps.setString(1, primaryGroup);
|
||||
ps.setString(2, uuid.toString());
|
||||
ps.execute();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
int i = userCounter.incrementAndGet();
|
||||
if (i % 100 == 0) {
|
||||
backing.getPlugin().getLog().info("Migrated " + i + " users so far...");
|
||||
}
|
||||
}
|
||||
|
||||
users.clear();
|
||||
|
||||
backing.getPlugin().getLog().info("Migrated all user data.");
|
||||
backing.getPlugin().getLog().info("Starting group data migration.");
|
||||
|
||||
Map<String, String> groupData = new HashMap<>();
|
||||
try (Connection c = backing.getProvider().getConnection()) {
|
||||
try (PreparedStatement ps = c.prepareStatement("SELECT name, perms FROM lp_groups")) {
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
while (rs.next()) {
|
||||
groupData.put(rs.getString("name"), rs.getString("perms"));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
backing.getPlugin().getLog().info("Found " + groupData.size() + " group data entries. Copying to new tables...");
|
||||
for (Map.Entry<String, String> e : groupData.entrySet()) {
|
||||
String name = e.getKey();
|
||||
String permsJson = e.getValue();
|
||||
|
||||
try (Connection c = backing.getProvider().getConnection()) {
|
||||
try (PreparedStatement ps = c.prepareStatement(backing.getPrefix().apply("INSERT INTO {prefix}groups VALUES(?)"))) {
|
||||
ps.setString(1, name);
|
||||
ps.execute();
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
Map<String, Boolean> convertedPerms = backing.getGson().fromJson(permsJson, NODE_MAP_TYPE);
|
||||
if (convertedPerms == null) {
|
||||
new Throwable().printStackTrace();
|
||||
continue;
|
||||
}
|
||||
|
||||
Set<NodeDataHolder> nodes = convertedPerms.entrySet().stream()
|
||||
.map(ent -> NodeFactory.fromSerialisedNode(ent.getKey(), ent.getValue()))
|
||||
.map(NodeDataHolder::fromNode)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
try (Connection c = backing.getProvider().getConnection()) {
|
||||
try (PreparedStatement ps = c.prepareStatement(backing.getPrefix().apply("INSERT INTO {prefix}group_permissions(name, permission, value, server, world, expiry, contexts) VALUES(?, ?, ?, ?, ?, ?, ?)"))) {
|
||||
for (NodeDataHolder nd : nodes) {
|
||||
ps.setString(1, name);
|
||||
ps.setString(2, nd.getPermission());
|
||||
ps.setBoolean(3, nd.isValue());
|
||||
ps.setString(4, nd.getServer());
|
||||
ps.setString(5, nd.getWorld());
|
||||
ps.setLong(6, nd.getExpiry());
|
||||
ps.setString(7, nd.getContexts());
|
||||
ps.addBatch();
|
||||
}
|
||||
ps.executeBatch();
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
groupData.clear();
|
||||
backing.getPlugin().getLog().info("Migrated all group data.");
|
||||
|
||||
backing.getPlugin().getLog().info("Renaming action and track tables.");
|
||||
try (Connection c = backing.getProvider().getConnection()) {
|
||||
try (PreparedStatement ps = c.prepareStatement(backing.getPrefix().apply("DROP TABLE {prefix}actions"))) {
|
||||
ps.execute();
|
||||
}
|
||||
try (PreparedStatement ps = c.prepareStatement(backing.getPrefix().apply("ALTER TABLE lp_actions RENAME TO {prefix}actions"))) {
|
||||
ps.execute();
|
||||
}
|
||||
|
||||
try (PreparedStatement ps = c.prepareStatement(backing.getPrefix().apply("DROP TABLE {prefix}tracks"))) {
|
||||
ps.execute();
|
||||
}
|
||||
try (PreparedStatement ps = c.prepareStatement(backing.getPrefix().apply("ALTER TABLE lp_tracks RENAME TO {prefix}tracks"))) {
|
||||
ps.execute();
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
backing.getPlugin().getLog().info("Legacy schema migration complete.");
|
||||
}
|
||||
}
|
@ -23,6 +23,7 @@
|
||||
package me.lucko.luckperms.common.storage.backing.utils;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
@ -38,6 +39,7 @@ import java.util.Map;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@EqualsAndHashCode
|
||||
@AllArgsConstructor(staticName = "of")
|
||||
public class NodeDataHolder {
|
||||
private static final Gson GSON = new Gson();
|
||||
|
@ -116,6 +116,10 @@ data {
|
||||
password=""
|
||||
pool-size=10 # The size of the MySQL connection pool.
|
||||
|
||||
# The prefix for all LuckPerms tables. Change this is you want to use different tables for different servers.
|
||||
# This should *not* be set to "lp_" if you have previously ran LuckPerms v2.16.81 or earlier with this database.
|
||||
table_prefix="luckperms_"
|
||||
|
||||
# Set to -1 to disable. If this is the only instance accessing the datastore, you can disable syncing.
|
||||
# e.g. if you're using sqlite or flatfile, this can be set to -1 to save resources.
|
||||
sync-minutes=3
|
||||
|
Loading…
Reference in New Issue
Block a user