Tab completion no longer blocks server thread

This commit is contained in:
Risto Lahtela 2020-09-21 14:52:21 +03:00
parent f8a977579b
commit 12fa5cf942
4 changed files with 137 additions and 30 deletions

View File

@ -30,7 +30,7 @@ public interface SubSystem {
*
* @throws EnableException If an error occurred during enable and it is fatal to the subsystem.
*/
void enable() throws EnableException;
void enable();
/**
* Performs disable actions for the subsystem

View File

@ -21,20 +21,14 @@ import com.djrapitops.plan.commands.use.Arguments;
import com.djrapitops.plan.commands.use.CMDSender;
import com.djrapitops.plan.commands.use.CommandWithSubcommands;
import com.djrapitops.plan.commands.use.Subcommand;
import com.djrapitops.plan.delivery.domain.auth.User;
import com.djrapitops.plan.gathering.importing.ImportSystem;
import com.djrapitops.plan.identification.Server;
import com.djrapitops.plan.settings.Permissions;
import com.djrapitops.plan.settings.locale.Locale;
import com.djrapitops.plan.settings.locale.lang.DeepHelpLang;
import com.djrapitops.plan.settings.locale.lang.HelpLang;
import com.djrapitops.plan.storage.database.DBSystem;
import com.djrapitops.plan.storage.database.DBType;
import com.djrapitops.plan.storage.database.queries.objects.ServerQueries;
import com.djrapitops.plan.storage.database.queries.objects.UserIdentifierQueries;
import com.djrapitops.plan.storage.database.queries.objects.WebUserQueries;
import com.djrapitops.plan.storage.file.PlanFiles;
import com.djrapitops.plan.utilities.java.Lists;
import com.djrapitops.plan.utilities.logging.ErrorContext;
import com.djrapitops.plan.utilities.logging.ErrorLogger;
import com.djrapitops.plugin.command.ColorScheme;
@ -43,24 +37,29 @@ import com.djrapitops.plugin.logging.L;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import java.util.*;
import java.util.stream.Collectors;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
@Singleton
public class PlanCommand {
private final String commandName;
private final PlanFiles files;
private final Locale locale;
private final ColorScheme colors;
private final Confirmation confirmation;
private final ImportSystem importSystem;
private final DBSystem dbSystem;
private final TabCompleteCache tabCompleteCache;
private final LinkCommands linkCommands;
private final RegistrationCommands registrationCommands;
private final PluginStatusCommands statusCommands;
private final DatabaseCommands databaseCommands;
private final DataUtilityCommands dataUtilityCommands;
private final PlanFiles files;
private final Locale locale;
private final ImportSystem importSystem;
private final DBSystem dbSystem;
private final ErrorLogger errorLogger;
@Inject
@ -70,6 +69,7 @@ public class PlanCommand {
Locale locale,
ColorScheme colors,
Confirmation confirmation,
TabCompleteCache tabCompleteCache,
ImportSystem importSystem,
DBSystem dbSystem,
LinkCommands linkCommands,
@ -84,6 +84,7 @@ public class PlanCommand {
this.locale = locale;
this.colors = colors;
this.confirmation = confirmation;
this.tabCompleteCache = tabCompleteCache;
this.importSystem = importSystem;
this.dbSystem = dbSystem;
this.linkCommands = linkCommands;
@ -141,13 +142,12 @@ public class PlanCommand {
public List<String> serverNames(CMDSender sender, Arguments arguments) {
String asString = arguments.concatenate(" ");
List<Server> servers = dbSystem.getDatabase().query(ServerQueries.findMatchingServers(asString));
return Lists.map(servers, Server::getIdentifiableName);
return tabCompleteCache.getMatchingServerIdentifiers(asString);
}
private List<String> playerNames(CMDSender sender, Arguments arguments) {
String asString = arguments.concatenate(" ");
return dbSystem.getDatabase().query(UserIdentifierQueries.fetchMatchingPlayerNames(asString));
return tabCompleteCache.getMatchingPlayerIdentifiers(asString);
}
private Subcommand serverCommand() {
@ -257,9 +257,7 @@ public class PlanCommand {
}
String username = arguments.concatenate(" ");
return dbSystem.getDatabase().query(WebUserQueries.matchUsers(username))
.stream().map(User::getUsername)
.collect(Collectors.toList());
return tabCompleteCache.getMatchingUserIdentifiers(username);
}
private Subcommand acceptCommand() {
@ -369,19 +367,10 @@ public class PlanCommand {
}
Optional<String> firstArgument = arguments.get(0);
if (!firstArgument.isPresent()) {
return Arrays.stream(files.getDataFolder().list())
.filter(Objects::nonNull)
.filter(fileName -> fileName.endsWith(".db")
&& !fileName.equalsIgnoreCase("database.db"))
.collect(Collectors.toList());
return tabCompleteCache.getMatchingPlayerIdentifiers(null);
}
String part = firstArgument.get();
return Arrays.stream(files.getDataFolder().list())
.filter(Objects::nonNull)
.filter(fileName -> fileName.startsWith(part)
&& fileName.endsWith(".db")
&& !fileName.equalsIgnoreCase("database.db"))
.collect(Collectors.toList());
return tabCompleteCache.getMatchingPlayerIdentifiers(part);
}
private Subcommand moveCommand() {

View File

@ -0,0 +1,113 @@
package com.djrapitops.plan.commands;
import com.djrapitops.plan.SubSystem;
import com.djrapitops.plan.delivery.domain.auth.User;
import com.djrapitops.plan.identification.Server;
import com.djrapitops.plan.storage.database.DBSystem;
import com.djrapitops.plan.storage.database.queries.objects.ServerQueries;
import com.djrapitops.plan.storage.database.queries.objects.UserIdentifierQueries;
import com.djrapitops.plan.storage.database.queries.objects.WebUserQueries;
import com.djrapitops.plan.storage.file.PlanFiles;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.*;
import java.util.stream.Collectors;
/**
* In charge of holding tab completion data for commands, as tab completion is done on server thread.
*
* @author Rsl1122
*/
@Singleton
public class TabCompleteCache implements SubSystem {
private final PlanFiles files;
private final DBSystem dbSystem;
private final List<String> playerIdentifiers;
private final List<String> serverIdentifiers;
private final List<String> userIdentifiers;
private final List<String> backupFileNames;
@Inject
public TabCompleteCache(
PlanFiles files,
DBSystem dbSystem
) {
this.files = files;
this.dbSystem = dbSystem;
playerIdentifiers = new ArrayList<>();
serverIdentifiers = new ArrayList<>();
userIdentifiers = new ArrayList<>();
backupFileNames = new ArrayList<>();
}
@Override
public void enable() {
refreshPlayerIdentifiers();
refreshServerIdentifiers();
refreshUserIdentifiers();
refreshBackupFileNames();
Collections.sort(playerIdentifiers);
Collections.sort(serverIdentifiers);
Collections.sort(userIdentifiers);
Collections.sort(backupFileNames);
}
private void refreshServerIdentifiers() {
Map<UUID, Server> serverNames = dbSystem.getDatabase().query(ServerQueries.fetchPlanServerInformation());
for (Map.Entry<UUID, Server> server : serverNames.entrySet()) {
serverIdentifiers.add(server.getKey().toString());
serverIdentifiers.add(server.getValue().getIdentifiableName());
serverIdentifiers.add(Integer.toString(server.getValue().getId()));
}
}
private void refreshPlayerIdentifiers() {
playerIdentifiers.addAll(dbSystem.getDatabase().query(UserIdentifierQueries.fetchAllPlayerNames()).values());
}
private void refreshUserIdentifiers() {
dbSystem.getDatabase().query(WebUserQueries.fetchAllUsers()).stream()
.map(User::getUsername)
.forEach(userIdentifiers::add);
}
private void refreshBackupFileNames() {
Arrays.stream(files.getDataFolder().list())
.filter(Objects::nonNull)
.filter(fileName -> fileName.endsWith(".db")
&& !fileName.equalsIgnoreCase("database.db"))
.forEach(backupFileNames::add);
}
@Override
public void disable() {
playerIdentifiers.clear();
serverIdentifiers.clear();
userIdentifiers.clear();
backupFileNames.clear();
}
public List<String> getMatchingServerIdentifiers(String searchFor) {
if (searchFor == null || searchFor.isEmpty()) return serverIdentifiers;
return serverIdentifiers.stream().filter(identifier -> identifier.startsWith(searchFor)).collect(Collectors.toList());
}
public List<String> getMatchingPlayerIdentifiers(String searchFor) {
if (searchFor == null || searchFor.isEmpty()) return playerIdentifiers;
return playerIdentifiers.stream().filter(identifier -> identifier.startsWith(searchFor)).collect(Collectors.toList());
}
public List<String> getMatchingUserIdentifiers(String searchFor) {
if (searchFor == null || searchFor.isEmpty()) return userIdentifiers;
return userIdentifiers.stream().filter(identifier -> identifier.startsWith(searchFor)).collect(Collectors.toList());
}
public List<String> getMatchingBackupFilenames(String searchFor) {
if (searchFor == null || searchFor.isEmpty()) return backupFileNames;
return backupFileNames.stream().filter(identifier -> identifier.startsWith(searchFor)).collect(Collectors.toList());
}
}

View File

@ -17,6 +17,7 @@
package com.djrapitops.plan.gathering.cache;
import com.djrapitops.plan.SubSystem;
import com.djrapitops.plan.commands.TabCompleteCache;
import com.djrapitops.plan.gathering.geolocation.GeolocationCache;
import javax.inject.Inject;
@ -30,16 +31,19 @@ import javax.inject.Singleton;
@Singleton
public class CacheSystem implements SubSystem {
private final TabCompleteCache tabCompleteCache;
private final SessionCache sessionCache;
private final NicknameCache nicknameCache;
private final GeolocationCache geolocationCache;
@Inject
public CacheSystem(
TabCompleteCache tabCompleteCache,
SessionCache sessionCache,
NicknameCache nicknameCache,
GeolocationCache geolocationCache
) {
this.tabCompleteCache = tabCompleteCache;
this.sessionCache = sessionCache;
this.nicknameCache = nicknameCache;
this.geolocationCache = geolocationCache;
@ -49,6 +53,7 @@ public class CacheSystem implements SubSystem {
public void enable() {
nicknameCache.enable();
geolocationCache.enable();
tabCompleteCache.enable();
}
@Override