mirror of
https://github.com/LuckPerms/LuckPerms.git
synced 2025-01-13 19:52:01 +01:00
Add flag to exclude users from an export (#961)
This commit is contained in:
parent
194b602fd6
commit
ab8b675bae
@ -79,12 +79,14 @@ public class Exporter implements Runnable {
|
|||||||
private final LuckPermsPlugin plugin;
|
private final LuckPermsPlugin plugin;
|
||||||
private final Sender executor;
|
private final Sender executor;
|
||||||
private final Path filePath;
|
private final Path filePath;
|
||||||
|
private final boolean includeUsers;
|
||||||
private final ProgressLogger log;
|
private final ProgressLogger log;
|
||||||
|
|
||||||
public Exporter(LuckPermsPlugin plugin, Sender executor, Path filePath) {
|
public Exporter(LuckPermsPlugin plugin, Sender executor, Path filePath, boolean includeUsers) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.executor = executor;
|
this.executor = executor;
|
||||||
this.filePath = filePath;
|
this.filePath = filePath;
|
||||||
|
this.includeUsers = includeUsers;
|
||||||
|
|
||||||
this.log = new ProgressLogger(null, Message.EXPORT_LOG, Message.EXPORT_LOG_PROGRESS);
|
this.log = new ProgressLogger(null, Message.EXPORT_LOG, Message.EXPORT_LOG_PROGRESS);
|
||||||
this.log.addListener(plugin.getConsoleSender());
|
this.log.addListener(plugin.getConsoleSender());
|
||||||
@ -169,101 +171,103 @@ public class Exporter implements Runnable {
|
|||||||
|
|
||||||
this.log.log("Exported " + tracks.size() + " tracks.");
|
this.log.log("Exported " + tracks.size() + " tracks.");
|
||||||
|
|
||||||
|
if (this.includeUsers) {
|
||||||
|
// Users are migrated in separate threads.
|
||||||
|
// This is because there are likely to be a lot of them, and because we can.
|
||||||
|
// It's a big speed improvement, since the database/files are split up and can handle concurrent reads.
|
||||||
|
|
||||||
// Users are migrated in separate threads.
|
this.log.log("Starting user export. Finding a list of unique users to export.");
|
||||||
// This is because there are likely to be a lot of them, and because we can.
|
|
||||||
// It's a big speed improvement, since the database/files are split up and can handle concurrent reads.
|
|
||||||
|
|
||||||
this.log.log("Starting user export. Finding a list of unique users to export.");
|
// Find all of the unique users we need to export
|
||||||
|
Storage ds = this.plugin.getStorage();
|
||||||
|
Set<UUID> users = ds.getUniqueUsers().join();
|
||||||
|
this.log.log("Found " + users.size() + " unique users to export.");
|
||||||
|
|
||||||
// Find all of the unique users we need to export
|
write(writer, "# Export users");
|
||||||
Storage ds = this.plugin.getStorage();
|
|
||||||
Set<UUID> users = ds.getUniqueUsers().join();
|
|
||||||
this.log.log("Found " + users.size() + " unique users to export.");
|
|
||||||
|
|
||||||
write(writer, "# Export users");
|
// create a threadpool to process the users concurrently
|
||||||
|
ExecutorService executor = Executors.newFixedThreadPool(32);
|
||||||
|
|
||||||
// create a threadpool to process the users concurrently
|
// Setup a file writing lock. We don't want multiple threads writing at the same time.
|
||||||
ExecutorService executor = Executors.newFixedThreadPool(32);
|
// The write function accepts a list of strings, as we want a user's data to be grouped together.
|
||||||
|
// This means it can be processed and added in one go.
|
||||||
// Setup a file writing lock. We don't want multiple threads writing at the same time.
|
ReentrantLock lock = new ReentrantLock();
|
||||||
// The write function accepts a list of strings, as we want a user's data to be grouped together.
|
Consumer<List<String>> writeFunction = strings -> {
|
||||||
// This means it can be processed and added in one go.
|
lock.lock();
|
||||||
ReentrantLock lock = new ReentrantLock();
|
try {
|
||||||
Consumer<List<String>> writeFunction = strings -> {
|
for (String s : strings) {
|
||||||
lock.lock();
|
write(writer, s);
|
||||||
try {
|
}
|
||||||
for (String s : strings) {
|
} finally {
|
||||||
write(writer, s);
|
lock.unlock();
|
||||||
}
|
}
|
||||||
} finally {
|
};
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// A set of futures, which are really just the processes we need to wait for.
|
// A set of futures, which are really just the processes we need to wait for.
|
||||||
Set<CompletableFuture<Void>> futures = new HashSet<>();
|
Set<CompletableFuture<Void>> futures = new HashSet<>();
|
||||||
|
|
||||||
AtomicInteger userCount = new AtomicInteger(0);
|
AtomicInteger userCount = new AtomicInteger(0);
|
||||||
|
|
||||||
// iterate through each user.
|
// iterate through each user.
|
||||||
for (UUID uuid : users) {
|
for (UUID uuid : users) {
|
||||||
// register a task for the user, and schedule it's execution with the pool
|
// register a task for the user, and schedule it's execution with the pool
|
||||||
futures.add(CompletableFuture.runAsync(() -> {
|
futures.add(CompletableFuture.runAsync(() -> {
|
||||||
// actually export the user. this output will be fed to the writing function when we have all of the user's data.
|
// actually export the user. this output will be fed to the writing function when we have all of the user's data.
|
||||||
List<String> output = new ArrayList<>();
|
List<String> output = new ArrayList<>();
|
||||||
|
|
||||||
User user = this.plugin.getStorage().loadUser(uuid, null).join();
|
User user = this.plugin.getStorage().loadUser(uuid, null).join();
|
||||||
output.add("# Export user: " + user.getUuid().toString() + " - " + user.getName().orElse("unknown username"));
|
output.add("# Export user: " + user.getUuid().toString() + " - " + user.getName().orElse("unknown username"));
|
||||||
|
|
||||||
boolean inDefault = false;
|
boolean inDefault = false;
|
||||||
for (Node node : user.enduringData().immutable().values()) {
|
for (Node node : user.enduringData().immutable().values()) {
|
||||||
if (node.isGroupNode() && node.getGroupName().equalsIgnoreCase(NodeFactory.DEFAULT_GROUP_NAME)) {
|
if (node.isGroupNode() && node.getGroupName().equalsIgnoreCase(NodeFactory.DEFAULT_GROUP_NAME)) {
|
||||||
inDefault = true;
|
inDefault = true;
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
output.add("/lp " + NodeFactory.nodeAsCommand(node, user.getUuid().toString(), HolderType.USER, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
output.add("/lp " + NodeFactory.nodeAsCommand(node, user.getUuid().toString(), HolderType.USER, true));
|
if (!user.getPrimaryGroup().getStoredValue().orElse(NodeFactory.DEFAULT_GROUP_NAME).equalsIgnoreCase(NodeFactory.DEFAULT_GROUP_NAME)) {
|
||||||
}
|
output.add("/lp user " + user.getUuid().toString() + " switchprimarygroup " + user.getPrimaryGroup().getStoredValue().get());
|
||||||
|
}
|
||||||
|
|
||||||
if (!user.getPrimaryGroup().getStoredValue().orElse(NodeFactory.DEFAULT_GROUP_NAME).equalsIgnoreCase(NodeFactory.DEFAULT_GROUP_NAME)) {
|
if (!inDefault) {
|
||||||
output.add("/lp user " + user.getUuid().toString() + " switchprimarygroup " + user.getPrimaryGroup().getStoredValue().get());
|
output.add("/lp user " + user.getUuid().toString() + " parent remove default");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!inDefault) {
|
this.plugin.getUserManager().cleanup(user);
|
||||||
output.add("/lp user " + user.getUuid().toString() + " parent remove default");
|
writeFunction.accept(output);
|
||||||
}
|
|
||||||
|
|
||||||
this.plugin.getUserManager().cleanup(user);
|
userCount.incrementAndGet();
|
||||||
writeFunction.accept(output);
|
}, executor));
|
||||||
|
|
||||||
userCount.incrementAndGet();
|
|
||||||
}, executor));
|
|
||||||
}
|
|
||||||
|
|
||||||
// all of the threads have been scheduled now and are running. we just need to wait for them all to complete
|
|
||||||
CompletableFuture<Void> overallFuture = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
try {
|
|
||||||
overallFuture.get(5, TimeUnit.SECONDS);
|
|
||||||
} catch (InterruptedException | ExecutionException e) {
|
|
||||||
// abnormal error - just break
|
|
||||||
e.printStackTrace();
|
|
||||||
break;
|
|
||||||
} catch (TimeoutException e) {
|
|
||||||
// still executing - send a progress report and continue waiting
|
|
||||||
this.log.logAllProgress("Exported {} users so far.", userCount.get());
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// process is complete
|
// all of the threads have been scheduled now and are running. we just need to wait for them all to complete
|
||||||
break;
|
CompletableFuture<Void> overallFuture = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
overallFuture.get(5, TimeUnit.SECONDS);
|
||||||
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
|
// abnormal error - just break
|
||||||
|
e.printStackTrace();
|
||||||
|
break;
|
||||||
|
} catch (TimeoutException e) {
|
||||||
|
// still executing - send a progress report and continue waiting
|
||||||
|
this.log.logAllProgress("Exported {} users so far.", userCount.get());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// process is complete
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
executor.shutdown();
|
||||||
|
this.log.log("Exported " + userCount.get() + " users.");
|
||||||
}
|
}
|
||||||
|
|
||||||
executor.shutdown();
|
|
||||||
|
|
||||||
this.log.log("Exported " + userCount.get() + " users.");
|
|
||||||
writer.flush();
|
writer.flush();
|
||||||
this.log.getListeners().forEach(l -> Message.LOG_EXPORT_SUCCESS.send(l, this.filePath.toFile().getAbsolutePath()));
|
this.log.getListeners().forEach(l -> Message.LOG_EXPORT_SUCCESS.send(l, this.filePath.toFile().getAbsolutePath()));
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ public class ExportCommand extends SingleCommand {
|
|||||||
private final AtomicBoolean running = new AtomicBoolean(false);
|
private final AtomicBoolean running = new AtomicBoolean(false);
|
||||||
|
|
||||||
public ExportCommand(LocaleManager locale) {
|
public ExportCommand(LocaleManager locale) {
|
||||||
super(CommandSpec.EXPORT.localize(locale), "Export", CommandPermission.EXPORT, Predicates.not(1));
|
super(CommandSpec.EXPORT.localize(locale), "Export", CommandPermission.EXPORT, Predicates.notInRange(1, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -57,6 +57,8 @@ public class ExportCommand extends SingleCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Path path = plugin.getBootstrap().getDataDirectory().resolve(args.get(0));
|
Path path = plugin.getBootstrap().getDataDirectory().resolve(args.get(0));
|
||||||
|
boolean includeUsers = !args.remove("--without-users");
|
||||||
|
|
||||||
if (Files.exists(path)) {
|
if (Files.exists(path)) {
|
||||||
Message.LOG_EXPORT_ALREADY_EXISTS.send(sender, path.toString());
|
Message.LOG_EXPORT_ALREADY_EXISTS.send(sender, path.toString());
|
||||||
return CommandResult.INVALID_ARGS;
|
return CommandResult.INVALID_ARGS;
|
||||||
@ -80,7 +82,7 @@ public class ExportCommand extends SingleCommand {
|
|||||||
return CommandResult.STATE_ERROR;
|
return CommandResult.STATE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
Exporter exporter = new Exporter(plugin, sender, path);
|
Exporter exporter = new Exporter(plugin, sender, path, includeUsers);
|
||||||
|
|
||||||
// Run the exporter in its own thread.
|
// Run the exporter in its own thread.
|
||||||
plugin.getBootstrap().getScheduler().doAsync(() -> {
|
plugin.getBootstrap().getScheduler().doAsync(() -> {
|
||||||
|
Loading…
Reference in New Issue
Block a user