Only save unique users

This commit is contained in:
Luck 2016-08-28 21:36:16 +01:00
parent 9f5e194a6e
commit 6aea3b53f3
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
21 changed files with 412 additions and 242 deletions

View File

@ -24,6 +24,7 @@ package me.lucko.luckperms.api;
import me.lucko.luckperms.api.data.Callback;
import java.util.Set;
import java.util.UUID;
/**
@ -90,7 +91,9 @@ public interface Datastore {
* @return true if the operation completed successfully.
* @throws NullPointerException if uuid or username is null
* @throws IllegalArgumentException if either of the parameters are invalid
* @deprecated functionality of this method is taken on by {@link #loadUser(UUID, String)}
*/
@Deprecated
boolean loadOrCreateUser(UUID uuid, String username);
/**
@ -98,9 +101,21 @@ public interface Datastore {
* @param uuid the uuid of the user to load
* @return true if the user exists, and was loaded correctly.
* @throws NullPointerException if uuid is null
* @deprecated replaced by {@link #loadUser(UUID, String)}
*/
@Deprecated
boolean loadUser(UUID uuid);
/**
* Loads a user's data into the plugins internal storage.
* @param uuid the uuid of the user to load
* @param username the users username. (if you want to specify <code>null</code> here, just input "null" as a string.)
* @return if the operation was performed successfully
* @throws NullPointerException if uuid or username is null
* @since 1.6
*/
boolean loadUser(UUID uuid, String username);
/**
* Saves a user object into the datastore. You should call this after you make any changes to a user.
* @param user the user to save
@ -110,6 +125,20 @@ public interface Datastore {
*/
boolean saveUser(User user);
/**
* Removes users from the datastore who are "default". This is called every time the plugin loads.
* @return true if the operation completed successfully
* @since 1.6
*/
boolean cleanupUsers();
/**
* Gets a set user's UUIDs who are "unique", aren't just a member of the "default" group.
* @return a set of uuids, or null if the operation failed.
* @since 1.6
*/
Set<UUID> getUniqueUsers();
/**
* Creates and loads a group into the plugins internal storage
* @param name the name of the group
@ -223,9 +252,14 @@ public interface Datastore {
interface Async {
void logAction(LogEntry entry, Callback<Boolean> callback);
void getLog(Callback<Log> callback);
@Deprecated
void loadOrCreateUser(UUID uuid, String username, Callback<Boolean> callback);
@Deprecated
void loadUser(UUID uuid, Callback<Boolean> callback);
void loadUser(UUID uuid, String username, Callback<Boolean> callback);
void saveUser(User user, Callback<Boolean> callback);
void cleanupUsers(Callback<Boolean> callback);
void getUniqueUsers(Callback<Set<UUID>> callback);
void createAndLoadGroup(String name, Callback<Boolean> callback);
void loadGroup(String name, Callback<Boolean> callback);
void loadAllGroups(Callback<Boolean> callback);
@ -250,9 +284,14 @@ public interface Datastore {
interface Future {
java.util.concurrent.Future<Boolean> logAction(LogEntry entry);
java.util.concurrent.Future<Log> getLog();
@Deprecated
java.util.concurrent.Future<Boolean> loadOrCreateUser(UUID uuid, String username);
@Deprecated
java.util.concurrent.Future<Boolean> loadUser(UUID uuid);
java.util.concurrent.Future<Boolean> loadUser(UUID uuid, String username);
java.util.concurrent.Future<Boolean> saveUser(User user);
java.util.concurrent.Future<Boolean> cleanupUsers();
java.util.concurrent.Future<Set<UUID>> getUniqueUsers();
java.util.concurrent.Future<Boolean> createAndLoadGroup(String name);
java.util.concurrent.Future<Boolean> loadGroup(String name);
java.util.concurrent.Future<Boolean> loadAllGroups();

View File

@ -39,6 +39,12 @@ public interface LuckPermsApi {
*/
void runUpdateTask();
/**
* @return the version of the API running on the platform
* @since 1.6
*/
double getApiVersion();
/**
* @return the version of the plugin running on the platform
*/

View File

@ -88,7 +88,7 @@ public class BukkitUserManager extends UserManager {
Set<UUID> players = plugin.getServer().getOnlinePlayers().stream()
.map(p -> plugin.getUuidCache().getUUID(p.getUniqueId()))
.collect(Collectors.toSet());
plugin.doAsync(() -> players.forEach(u -> plugin.getDatastore().loadUser(u)));
plugin.doAsync(() -> players.forEach(u -> plugin.getDatastore().loadUser(u, "null")));
});
}
}

View File

@ -97,7 +97,7 @@ public class BungeeListener extends AbstractListener implements Listener {
// We have to make a new user on this thread whilst the connection is being held, or we get concurrency issues as the Bukkit server
// and the BungeeCord server try to make a new user at the same time.
plugin.getDatastore().loadOrCreateUser(cache.getUUID(c.getUniqueId()), c.getName());
plugin.getDatastore().loadUser(cache.getUUID(c.getUniqueId()), c.getName());
final long time = System.currentTimeMillis() - startTime;
if (time >= 1000) {
plugin.getLog().warn("Processing login for " + c.getName() + " took " + time + "ms.");

View File

@ -64,6 +64,6 @@ public class BungeeUserManager extends UserManager {
public void updateAllUsers() {
plugin.getProxy().getPlayers().stream()
.map(p -> plugin.getUuidCache().getUUID(p.getUniqueId()))
.forEach(u -> plugin.getDatastore().loadUser(u));
.forEach(u -> plugin.getDatastore().loadUser(u, "null"));
}
}

View File

@ -66,6 +66,11 @@ public class ApiProvider implements LuckPermsApi {
plugin.runUpdateTask();
}
@Override
public double getApiVersion() {
return 1.6;
}
@Override
public String getVersion() {
return plugin.getVersion();

View File

@ -30,8 +30,10 @@ import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.api.*;
import me.lucko.luckperms.api.data.Callback;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@ -106,12 +108,17 @@ public class DatastoreLink implements Datastore {
@Override
public void loadOrCreateUser(@NonNull UUID uuid, @NonNull String username, Callback<Boolean> callback) {
master.loadOrCreateUser(uuid, checkUsername(username), checkCallback(callback));
master.loadUser(uuid, checkUsername(username), checkCallback(callback));
}
@Override
public void loadUser(@NonNull UUID uuid, Callback<Boolean> callback) {
master.loadUser(uuid, checkCallback(callback));
master.loadUser(uuid, "null", checkCallback(callback));
}
@Override
public void loadUser(@NonNull UUID uuid, @NonNull String username, Callback<Boolean> callback) {
master.loadUser(uuid, checkUsername(username), checkCallback(callback));
}
@Override
@ -120,6 +127,16 @@ public class DatastoreLink implements Datastore {
master.saveUser(((UserLink) user).getMaster(), checkCallback(callback));
}
@Override
public void cleanupUsers(Callback<Boolean> callback) {
master.cleanupUsers(checkCallback(callback));
}
@Override
public void getUniqueUsers(Callback<Set<UUID>> callback) {
master.getUniqueUsers(checkCallback(callback));
}
@Override
public void createAndLoadGroup(@NonNull String name, Callback<Boolean> callback) {
master.createAndLoadGroup(checkName(name), checkCallback(callback));
@ -204,12 +221,17 @@ public class DatastoreLink implements Datastore {
@Override
public boolean loadOrCreateUser(@NonNull UUID uuid, @NonNull String username) {
return master.loadOrCreateUser(uuid, checkUsername(username));
return master.loadUser(uuid, checkUsername(username));
}
@Override
public boolean loadUser(@NonNull UUID uuid) {
return master.loadUser(uuid);
return master.loadUser(uuid, "null");
}
@Override
public boolean loadUser(@NonNull UUID uuid, @NonNull String username) {
return master.loadUser(uuid, checkUsername(username));
}
@Override
@ -218,6 +240,16 @@ public class DatastoreLink implements Datastore {
return master.saveUser(((UserLink) user).getMaster());
}
@Override
public boolean cleanupUsers() {
return master.cleanupUsers();
}
@Override
public Set<UUID> getUniqueUsers() {
return master.getUniqueUsers();
}
@Override
public boolean createAndLoadGroup(@NonNull String name) {
return master.createAndLoadGroup(checkName(name));
@ -307,14 +339,21 @@ public class DatastoreLink implements Datastore {
@Override
public java.util.concurrent.Future<Boolean> loadOrCreateUser(@NonNull UUID uuid, @NonNull String username) {
LPFuture<Boolean> lpf = new LPFuture<>();
master.loadOrCreateUser(uuid, checkUsername(username), lpf);
master.loadUser(uuid, checkUsername(username), lpf);
return lpf;
}
@Override
public java.util.concurrent.Future<Boolean> loadUser(@NonNull UUID uuid) {
LPFuture<Boolean> lpf = new LPFuture<>();
master.loadUser(uuid, lpf);
master.loadUser(uuid, "null", lpf);
return lpf;
}
@Override
public java.util.concurrent.Future<Boolean> loadUser(@NonNull UUID uuid, @NonNull String username) {
LPFuture<Boolean> lpf = new LPFuture<>();
master.loadUser(uuid, checkUsername(username), lpf);
return lpf;
}
@ -326,6 +365,20 @@ public class DatastoreLink implements Datastore {
return lpf;
}
@Override
public java.util.concurrent.Future<Boolean> cleanupUsers() {
LPFuture<Boolean> lpf = new LPFuture<>();
master.cleanupUsers(lpf);
return lpf;
}
@Override
public java.util.concurrent.Future<Set<UUID>> getUniqueUsers() {
LPFuture<Set<UUID>> lpf = new LPFuture<>();
master.getUniqueUsers(lpf);
return lpf;
}
@Override
public java.util.concurrent.Future<Boolean> createAndLoadGroup(@NonNull String name) {
LPFuture<Boolean> lpf = new LPFuture<>();

View File

@ -188,7 +188,7 @@ public class MigrationBungeePerms extends SubCommand<Object> {
userCount++;
// Make a LuckPerms user for the one being migrated.
plugin.getDatastore().loadOrCreateUser(u.getUUID(), "null");
plugin.getDatastore().loadUser(u.getUUID(), "null");
me.lucko.luckperms.users.User user = plugin.getUserManager().get(u.getUUID());
// Migrate global perms

View File

@ -246,7 +246,7 @@ public class MigrationGroupManager extends SubCommand<Object> {
}
for (Map.Entry<UUID, Map<Map.Entry<String, String>, Boolean>> e : users.entrySet()) {
plugin.getDatastore().loadOrCreateUser(e.getKey(), "null");
plugin.getDatastore().loadUser(e.getKey(), "null");
me.lucko.luckperms.users.User user = plugin.getUserManager().get(e.getKey());
for (Map.Entry<Map.Entry<String, String>, Boolean> n : e.getValue().entrySet()) {

View File

@ -286,7 +286,7 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
}
userCount++;
plugin.getDatastore().loadOrCreateUser(u, "null");
plugin.getDatastore().loadUser(u, "null");
User lpUser = plugin.getUserManager().get(u);
try {

View File

@ -212,7 +212,7 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
progress.put(uuid, new CountDownLatch(2));
// Create a LuckPerms user for the UUID
plugin.getDatastore().loadOrCreateUser(uuid, "null");
plugin.getDatastore().loadUser(uuid, "null");
User user = plugin.getUserManager().get(uuid);
// Get a list of Permissions held by the user from the PP API.

View File

@ -152,7 +152,7 @@ public class MigrationZPermissions extends SubCommand<Object> {
// Migrate all users.
log.info("zPermissions Migration: Starting user migration.");
for (UUID u : service.getAllPlayersUUID()) {
plugin.getDatastore().loadOrCreateUser(u, "null");
plugin.getDatastore().loadUser(u, "null");
User user = plugin.getUserManager().get(u);
for (Map.Entry<String, Boolean> e : service.getPlayerPermissions(null, null, u).entrySet()) {

View File

@ -65,64 +65,43 @@ public class UserMainCommand extends MainCommand<User> {
@Override
protected User getTarget(String target, LuckPermsPlugin plugin, Sender sender) {
UUID u = Util.parseUuid(target);
if (u != null) {
User user = getUser(plugin, u);
if (user == null) {
Message.USER_NEVER_JOINED.send(sender);
if (!plugin.getDatastore().loadOrCreateUser(u, "null")) {
Message.USER_CREATE_FAIL.send(sender);
if (u == null) {
if (target.length() <= 16) {
if (Patterns.NON_USERNAME.matcher(target).find()) {
Message.USER_INVALID_ENTRY.send(sender, target);
return null;
}
user = getUser(plugin, u);
}
return user;
}
Message.USER_ATTEMPTING_LOOKUP.send(sender);
if (target.length() <= 16) {
if (Patterns.NON_USERNAME.matcher(target).find()) {
u = plugin.getDatastore().getUUID(target);
if (u == null) {
Message.USER_NOT_FOUND.send(sender);
return null;
}
} else {
Message.USER_INVALID_ENTRY.send(sender, target);
return null;
}
Message.USER_ATTEMPTING_LOOKUP.send(sender);
UUID uuid = plugin.getDatastore().getUUID(target);
if (uuid == null) {
Message.USER_NOT_FOUND.send(sender);
return null;
}
User user = getUser(plugin, uuid);
if (user == null) {
Message.USER_NOT_FOUND.send(sender);
}
return user;
}
Message.USER_INVALID_ENTRY.send(sender, target);
return null;
}
@Override
protected void cleanup(User user, LuckPermsPlugin plugin) {
plugin.getUserManager().cleanup(user);
}
private User getUser(LuckPermsPlugin plugin, UUID uuid) {
if (!plugin.getDatastore().loadUser(uuid)) {
return null;
if (!plugin.getDatastore().loadUser(u, "null")) {
Message.LOADING_ERROR.send(sender);
}
User user = plugin.getUserManager().get(uuid);
User user = plugin.getUserManager().get(u);
if (user == null) {
Message.LOADING_ERROR.send(sender);
return null;
}
return user;
}
@Override
protected void cleanup(User user, LuckPermsPlugin plugin) {
plugin.getUserManager().cleanup(user);
}
@Override
protected List<String> getObjects(LuckPermsPlugin plugin) {
return plugin.getPlayerList();

View File

@ -60,7 +60,6 @@ public enum Message {
USER_SAVE_SUCCESS("&7(User data was saved to the datastore)", true),
USER_SAVE_ERROR("There was an error whilst saving the user.", true),
USER_ATTEMPTING_LOOKUP("&7(Attempting UUID lookup, since you specified a username)", true),
USER_NEVER_JOINED("&6(&e&lWARNING: &cA user with that UUID has not joined the server before.&6)", true),
USER_CREATE_FAIL("There was an error whilst creating a new user.", true),
GROUP_NOT_FOUND("&eGroup could not be found.", true),

View File

@ -34,6 +34,7 @@ import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.tracks.Track;
import me.lucko.luckperms.users.User;
import java.util.Set;
import java.util.UUID;
@RequiredArgsConstructor(access = AccessLevel.PROTECTED)
@ -70,9 +71,10 @@ public abstract class Datastore {
public abstract void shutdown();
public abstract boolean logAction(LogEntry entry);
public abstract Log getLog();
public abstract boolean loadOrCreateUser(UUID uuid, String username);
public abstract boolean loadUser(UUID uuid);
public abstract boolean loadUser(UUID uuid, String username);
public abstract boolean saveUser(User user);
public abstract boolean cleanupUsers();
public abstract Set<UUID> getUniqueUsers();
public abstract boolean createAndLoadGroup(String name);
public abstract boolean loadGroup(String name);
public abstract boolean loadAllGroups();
@ -106,16 +108,9 @@ public abstract class Datastore {
});
}
public void loadOrCreateUser(UUID uuid, String username, Callback<Boolean> callback) {
public void loadUser(UUID uuid, String username, Callback<Boolean> callback) {
doAsync(() -> {
boolean result = loadOrCreateUser(uuid, username);
doSync(() -> callback.onComplete(result));
});
}
public void loadUser(UUID uuid, Callback<Boolean> callback) {
doAsync(() -> {
boolean result = loadUser(uuid);
boolean result = loadUser(uuid, username);
doSync(() -> callback.onComplete(result));
});
}
@ -127,6 +122,20 @@ public abstract class Datastore {
});
}
public void cleanupUsers(Callback<Boolean> callback) {
doAsync(() -> {
boolean result = cleanupUsers();
doSync(() -> callback.onComplete(result));
});
}
public void getUniqueUsers(Callback<Set<UUID>> callback) {
doAsync(() -> {
Set<UUID> result = getUniqueUsers();
doSync(() -> callback.onComplete(result));
});
}
public void createAndLoadGroup(String name, Callback<Boolean> callback) {
doAsync(() -> {
boolean result = createAndLoadGroup(name);

View File

@ -118,6 +118,8 @@ public class FlatfileDatastore extends Datastore {
e.printStackTrace();
}
cleanupUsers();
setAcceptingLogins(true);
}
@ -166,108 +168,58 @@ public class FlatfileDatastore extends Datastore {
}
@Override
public boolean loadOrCreateUser(UUID uuid, String username) {
public boolean loadUser(UUID uuid, String username) {
User user = plugin.getUserManager().make(uuid, username);
boolean success = false;
File userFile = new File(usersDir, uuid.toString() + ".json");
if (!userFile.exists()) {
try {
userFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
return false;
}
boolean success = doWrite(userFile, writer -> {
writer.beginObject();
writer.name("uuid").value(user.getUuid().toString());
writer.name("name").value(user.getName());
writer.name("primaryGroup").value(user.getPrimaryGroup());
writer.name("perms");
writer.beginObject();
for (Map.Entry<String, Boolean> e : exportToLegacy(user.getNodes()).entrySet()) {
writer.name(e.getKey()).value(e.getValue().booleanValue());
if (userFile.exists()) {
final String[] name = new String[1];
success = doRead(userFile, reader -> {
reader.beginObject();
reader.nextName(); // uuid record
reader.nextString(); // uuid
reader.nextName(); // name record
name[0] = reader.nextString(); // name
reader.nextName(); // primaryGroup record
user.setPrimaryGroup(reader.nextString()); // primaryGroup
reader.nextName(); //perms
reader.beginObject();
while (reader.hasNext()) {
String node = reader.nextName();
boolean b = reader.nextBoolean();
user.getNodes().add(Node.fromSerialisedNode(node, b));
}
writer.endObject();
writer.endObject();
reader.endObject();
reader.endObject();
return true;
});
if (!success) return false;
}
final String[] name = new String[1];
boolean success = doRead(userFile, reader -> {
reader.beginObject();
reader.nextName(); // uuid record
reader.nextString(); // uuid
reader.nextName(); // name record
name[0] = reader.nextString(); // name
reader.nextName(); // primaryGroup record
user.setPrimaryGroup(reader.nextString()); // primaryGroup
reader.nextName(); //perms
reader.beginObject();
while (reader.hasNext()) {
String node = reader.nextName();
boolean b = reader.nextBoolean();
user.getNodes().add(Node.fromSerialisedNode(node, b));
}
reader.endObject();
reader.endObject();
return true;
});
if (!name[0].equals(user.getName())) {
doWrite(userFile, writer -> {
writer.beginObject();
writer.name("uuid").value(user.getUuid().toString());
writer.name("name").value(user.getName());
writer.name("primaryGroup").value(user.getPrimaryGroup());
writer.name("perms");
writer.beginObject();
for (Map.Entry<String, Boolean> e : exportToLegacy(user.getNodes()).entrySet()) {
writer.name(e.getKey()).value(e.getValue().booleanValue());
if (user.getName().equalsIgnoreCase("null")) {
user.setName(name[0]);
} else {
if (!name[0].equals(user.getName())) {
doWrite(userFile, writer -> {
writer.beginObject();
writer.name("uuid").value(user.getUuid().toString());
writer.name("name").value(user.getName());
writer.name("primaryGroup").value(user.getPrimaryGroup());
writer.name("perms");
writer.beginObject();
for (Map.Entry<String, Boolean> e : exportToLegacy(user.getNodes()).entrySet()) {
writer.name(e.getKey()).value(e.getValue().booleanValue());
}
writer.endObject();
writer.endObject();
return true;
});
}
writer.endObject();
writer.endObject();
return true;
});
}
if (success) plugin.getUserManager().updateOrSet(user);
return success;
}
@Override
public boolean loadUser(UUID uuid) {
User user = plugin.getUserManager().make(uuid);
File userFile = new File(usersDir, uuid.toString() + ".json");
if (!userFile.exists()) {
return false;
}
boolean success = doRead(userFile, reader -> {
reader.beginObject();
reader.nextName(); // uuid record
reader.nextString(); // uuid
reader.nextName(); // name record
user.setName(reader.nextString()); // name
reader.nextName(); // primaryGroup record
user.setPrimaryGroup(reader.nextString()); // primaryGroup
reader.nextName(); // perms record
reader.beginObject();
while (reader.hasNext()) {
String node = reader.nextName();
boolean b = reader.nextBoolean();
user.getNodes().add(Node.fromSerialisedNode(node, b));
}
reader.endObject();
reader.endObject();
return true;
});
} else {
success = true;
}
if (success) plugin.getUserManager().updateOrSet(user);
return success;
@ -302,6 +254,59 @@ public class FlatfileDatastore extends Datastore {
return success;
}
@Override
public boolean cleanupUsers() {
File[] files = usersDir.listFiles((dir, name) -> name.endsWith(".json"));
if (files == null) return false;
for (File file : files) {
Map<String, Boolean> nodes = new HashMap<>();
doRead(file, reader -> {
reader.beginObject();
reader.nextName(); // uuid record
reader.nextString(); // uuid
reader.nextName(); // name record
reader.nextString(); // name
reader.nextName(); // primaryGroup record
reader.nextString(); // primaryGroup
reader.nextName(); //perms
reader.beginObject();
while (reader.hasNext()) {
String node = reader.nextName();
boolean b = reader.nextBoolean();
nodes.put(node, b);
}
reader.endObject();
reader.endObject();
return true;
});
boolean shouldDelete = false;
if (nodes.size() == 1) {
for (Map.Entry<String, Boolean> e : nodes.entrySet()) {
// There's only one
shouldDelete = e.getKey().equalsIgnoreCase("group.default") && e.getValue();
}
}
if (shouldDelete) {
file.delete();
}
}
return true;
}
@Override
public Set<UUID> getUniqueUsers() {
String[] fileNames = usersDir.list((dir, name) -> name.endsWith(".json"));
if (fileNames == null) return null;
return Arrays.stream(fileNames)
.map(s -> s.substring(0, s.length() - 5))
.map(UUID::fromString)
.collect(Collectors.toSet());
}
@Override
public boolean createAndLoadGroup(String name) {
Group group = plugin.getGroupManager().make(name);

View File

@ -139,21 +139,23 @@ public class MongoDBDatastore extends Datastore {
}
@Override
public boolean loadOrCreateUser(UUID uuid, String username) {
public boolean loadUser(UUID uuid, String username) {
User user = plugin.getUserManager().make(uuid, username);
boolean success = call(() -> {
MongoCollection<Document> c = database.getCollection("users");
try (MongoCursor<Document> cursor = c.find(new Document("_id", user.getUuid())).iterator()) {
if (!cursor.hasNext()) {
c.insertOne(fromUser(user));
} else {
if (cursor.hasNext()) {
Document d = cursor.next();
user.setPrimaryGroup(d.getString("primaryGroup"));
user.setNodes(revert((Map<String, Boolean>) d.get("perms")));
if (!d.getString("name").equals(user.getName())) {
c.replaceOne(new Document("_id", user.getUuid()), fromUser(user));
if (user.getName().equalsIgnoreCase("null")) {
user.setName(d.getString("name"));
} else {
if (!d.getString("name").equals(user.getName())) {
c.replaceOne(new Document("_id", user.getUuid()), fromUser(user));
}
}
}
}
@ -165,34 +167,47 @@ public class MongoDBDatastore extends Datastore {
}
@Override
public boolean loadUser(UUID uuid) {
User user = plugin.getUserManager().make(uuid);
public boolean saveUser(User user) {
if (!plugin.getUserManager().shouldSave(user)) {
return true;
}
boolean success = call(() -> {
MongoCollection<Document> c = database.getCollection("users");
try (MongoCursor<Document> cursor = c.find(new Document("_id", user.getUuid())).iterator()) {
if (cursor.hasNext()) {
Document d = cursor.next();
user.setName(d.getString("name"));
user.setPrimaryGroup(d.getString("primaryGroup"));
user.setNodes(revert((Map<String, Boolean>) d.get("perms")));
return true;
if (!cursor.hasNext()) {
c.insertOne(fromUser(user));
} else {
c.replaceOne(new Document("_id", user.getUuid()), fromUser(user));
}
return false;
}
return true;
}, false);
if (success) plugin.getUserManager().updateOrSet(user);
return success;
}
@Override
public boolean saveUser(User user) {
return call(() -> {
public boolean cleanupUsers() {
return true; // TODO
}
@Override
public Set<UUID> getUniqueUsers() {
Set<UUID> uuids = new HashSet<>();
boolean success = call(() -> {
MongoCollection<Document> c = database.getCollection("users");
c.replaceOne(new Document("_id", user.getUuid()), fromUser(user));
try (MongoCursor<Document> cursor = c.find().iterator()) {
while (cursor.hasNext()) {
Document d = cursor.next();
uuids.add(UUID.fromString(d.getString("_id")));
}
}
return true;
}, false);
return success ? uuids : null;
}
@Override

View File

@ -41,10 +41,7 @@ import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.*;
import static me.lucko.luckperms.core.PermissionHolder.exportToLegacy;
@ -56,7 +53,9 @@ abstract class SQLDatastore extends Datastore {
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 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=?";
@ -95,33 +94,7 @@ abstract class SQLDatastore extends Datastore {
if (!runQuery(new Query(q))) success = false;
}
return success;
}
@Override
public boolean loadUser(UUID uuid) {
User user = plugin.getUserManager().make(uuid);
boolean success = runQuery(new QueryRS(USER_SELECT) {
@Override
void onRun(PreparedStatement preparedStatement) throws SQLException {
preparedStatement.setString(1, uuid.toString());
}
@Override
boolean onResult(ResultSet resultSet) throws SQLException {
if (resultSet.next()) {
user.setName(resultSet.getString("name"));
Map<String, Boolean> nodes = gson.fromJson(resultSet.getString("perms"), NM_TYPE);
user.setNodes(nodes);
user.setPrimaryGroup(resultSet.getString("primary_group"));
return true;
}
return false;
}
});
if (success) plugin.getUserManager().updateOrSet(user);
return success;
return success && cleanupUsers();
}
@Override
@ -172,7 +145,7 @@ abstract class SQLDatastore extends Datastore {
}
@Override
public boolean loadOrCreateUser(UUID uuid, String username) {
public boolean loadUser(UUID uuid, String username) {
User user = plugin.getUserManager().make(uuid, username);
boolean success = runQuery(new QueryRS(USER_SELECT) {
@Override
@ -182,35 +155,29 @@ abstract class SQLDatastore extends Datastore {
@Override
boolean onResult(ResultSet resultSet) throws SQLException {
boolean success = true;
if (!resultSet.next()) {
success = runQuery(new QueryPS(USER_INSERT) {
@Override
void onRun(PreparedStatement preparedStatement) throws SQLException {
preparedStatement.setString(1, user.getUuid().toString());
preparedStatement.setString(2, user.getName());
preparedStatement.setString(3, user.getPrimaryGroup());
preparedStatement.setString(4, gson.toJson(exportToLegacy(user.getNodes())));
}
});
} else {
if (resultSet.next()) {
// User exists, let's load.
Map<String, Boolean> nodes = gson.fromJson(resultSet.getString("perms"), NM_TYPE);
user.setNodes(nodes);
user.setPrimaryGroup(resultSet.getString("primary_group"));
if (!resultSet.getString("name").equals(user.getName())) {
runQuery(new QueryPS(USER_UPDATE) {
@Override
void onRun(PreparedStatement preparedStatement) throws SQLException {
preparedStatement.setString(1, user.getName());
preparedStatement.setString(2, user.getPrimaryGroup());
preparedStatement.setString(3, gson.toJson(exportToLegacy(user.getNodes())));
preparedStatement.setString(4, user.getUuid().toString());
}
});
if (user.getName().equalsIgnoreCase("null")) {
user.setName(resultSet.getString("name"));
} else {
if (!resultSet.getString("name").equals(user.getName())) {
runQuery(new QueryPS(USER_UPDATE) {
@Override
void onRun(PreparedStatement preparedStatement) throws SQLException {
preparedStatement.setString(1, user.getName());
preparedStatement.setString(2, user.getPrimaryGroup());
preparedStatement.setString(3, gson.toJson(exportToLegacy(user.getNodes())));
preparedStatement.setString(4, user.getUuid().toString());
}
});
}
}
}
return success;
return true;
}
});
@ -220,18 +187,83 @@ abstract class SQLDatastore extends Datastore {
@Override
public boolean saveUser(User user) {
boolean success = runQuery(new QueryPS(USER_UPDATE) {
if (!plugin.getUserManager().shouldSave(user)) {
return true;
}
boolean success = runQuery(new QueryRS(USER_SELECT) {
@Override
void onRun(PreparedStatement preparedStatement) throws SQLException {
preparedStatement.setString(1, user.getName());
preparedStatement.setString(2, user.getPrimaryGroup());
preparedStatement.setString(3, gson.toJson(exportToLegacy(user.getNodes())));
preparedStatement.setString(4, user.getUuid().toString());
preparedStatement.setString(1, user.getUuid().toString());
}
@Override
boolean onResult(ResultSet resultSet) throws SQLException {
boolean b;
if (!resultSet.next()) {
// Doesn't already exist, let's insert.
b = runQuery(new QueryPS(USER_INSERT) {
@Override
void onRun(PreparedStatement preparedStatement) throws SQLException {
preparedStatement.setString(1, user.getUuid().toString());
preparedStatement.setString(2, user.getName());
preparedStatement.setString(3, user.getPrimaryGroup());
preparedStatement.setString(4, gson.toJson(exportToLegacy(user.getNodes())));
}
});
} else {
// User exists, let's update.
b = runQuery(new QueryPS(USER_UPDATE) {
@Override
void onRun(PreparedStatement preparedStatement) throws SQLException {
preparedStatement.setString(1, user.getName());
preparedStatement.setString(2, user.getPrimaryGroup());
preparedStatement.setString(3, gson.toJson(exportToLegacy(user.getNodes())));
preparedStatement.setString(4, user.getUuid().toString());
}
});
}
return b;
}
});
return success;
}
@Override
public boolean cleanupUsers() {
boolean success = runQuery(new QueryPS(USER_DELETE) {
@Override
void onRun(PreparedStatement preparedStatement) throws SQLException {
preparedStatement.setString(1, "{\"group.default\":true}");
}
});
return success;
}
@Override
public Set<UUID> getUniqueUsers() {
Set<UUID> uuids = new HashSet<>();
boolean success = runQuery(new QueryRS(USER_SELECT_ALL) {
@Override
void onRun(PreparedStatement preparedStatement) throws SQLException {
}
@Override
boolean onResult(ResultSet resultSet) throws SQLException {
while (resultSet.next()) {
String uuid = resultSet.getString("uuid");
uuids.add(UUID.fromString(uuid));
}
return false;
}
});
return success ? uuids : null;
}
@Override
public boolean createAndLoadGroup(String name) {
Group group = plugin.getGroupManager().make(name);

View File

@ -93,6 +93,34 @@ public abstract class UserManager extends AbstractManager<UUID, User> {
}
}
public boolean shouldSave(User user) {
if (user.getNodes().size() != 1) {
return true;
}
for (Node node : user.getNodes()) {
// There's only one.
if (!node.isGroupNode()) {
return true;
}
if (node.isTemporary() || node.isServerSpecific() || node.isWorldSpecific()) {
return true;
}
if (!node.getGroupName().equalsIgnoreCase("default")) {
// The user's only node is not the default group one.
return true;
}
}
if (!user.getPrimaryGroup().equalsIgnoreCase("default")) {
return true; // Not in the default primary group
}
return false;
}
/**
* Checks to see if the user is online, and if they are not, runs {@link #unload(Identifiable)}
* @param user The user to be cleaned up

View File

@ -59,7 +59,7 @@ public class AbstractListener {
plugin.getDatastore().saveUUIDData(username, u, Callback.empty());
}
plugin.getDatastore().loadOrCreateUser(cache.getUUID(u), username);
plugin.getDatastore().loadUser(cache.getUUID(u), username);
final long time = System.currentTimeMillis() - startTime;
if (time >= 1000) {
plugin.getLog().warn("Processing login for " + username + " took " + time + "ms.");

View File

@ -62,6 +62,6 @@ public class SpongeUserManager extends UserManager {
public void updateAllUsers() {
plugin.getGame().getServer().getOnlinePlayers().stream()
.map(p -> plugin.getUuidCache().getUUID(p.getUniqueId()))
.forEach(u -> plugin.getDatastore().loadUser(u));
.forEach(u -> plugin.getDatastore().loadUser(u, "null"));
}
}