Skip to content

Commit

Permalink
feat: Improved CompletableFuture usage
Browse files Browse the repository at this point in the history
Now errors are handled in a better way

feat: Use Caffeine's Cache instead of ConcurrentHashMaps
feat: Improved regular infractions replaceable results
  • Loading branch information
4drian3d committed May 5, 2022
1 parent ff83bcf commit 32978c2
Show file tree
Hide file tree
Showing 21 changed files with 192 additions and 157 deletions.
3 changes: 2 additions & 1 deletion build.gradle.kts
Expand Up @@ -25,6 +25,7 @@ java {

dependencies {
compileOnly("org.spongepowered:configurate-hocon:4.1.2")
compileOnly("com.github.ben-manes.caffeine:caffeine:3.0.6")
shadow("org.jetbrains:annotations:23.0.0")
shadow("net.byteflux:libby-velocity:1.1.5")

Expand All @@ -39,7 +40,7 @@ dependencies {
testImplementation("org.junit.jupiter:junit-jupiter")
testImplementation("org.mockito:mockito-core:4.1.0")
testImplementation("com.velocitypowered:velocity-api:3.1.2-SNAPSHOT")

testImplementation("com.github.ben-manes.caffeine:caffeine:3.0.6")
}

group = "me.dreamerzero.chatregulator"
Expand Down
18 changes: 15 additions & 3 deletions src/main/java/me/dreamerzero/chatregulator/ChatRegulator.java
Expand Up @@ -3,8 +3,9 @@
import java.nio.file.Path;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.google.inject.Inject;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
Expand Down Expand Up @@ -64,7 +65,7 @@ public class ChatRegulator {
/**
* InfractionPlayer list
*/
protected static final Map<UUID, InfractionPlayer> infractionPlayers = new ConcurrentHashMap<>();
protected static final Cache<UUID, InfractionPlayer> infractionPlayers = Caffeine.newBuilder().weakKeys().build();

/**
* Constructor for ChatRegulator Plugin
Expand Down Expand Up @@ -155,7 +156,7 @@ public IFormatter getFormatter(){
}

public Map<UUID, InfractionPlayer> getChatPlayers(){
return infractionPlayers;
return infractionPlayers.asMap();
}

/**
Expand Down Expand Up @@ -186,10 +187,21 @@ private void loadDependencies() {
.version("1.3.13")
.id("geantyref")
.build();
final Library caffeine = Library.builder()
.groupId("com{}github{}ben-manes{}caffeine")
.artifactId("caffeine")
.version("3.0.6")
.id("caffeine")
.build();

libraryManager.addMavenCentral();
libraryManager.loadLibrary(hocon);
libraryManager.loadLibrary(confCore);
libraryManager.loadLibrary(geantyref);
libraryManager.loadLibrary(caffeine);
}

public void removePlayer(UUID uuid) {
infractionPlayers.invalidate(uuid);
}
}
60 changes: 14 additions & 46 deletions src/main/java/me/dreamerzero/chatregulator/InfractionPlayer.java
Expand Up @@ -3,7 +3,6 @@
import java.time.Duration;
import java.time.Instant;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;

import com.velocitypowered.api.proxy.Player;
Expand Down Expand Up @@ -52,25 +51,6 @@ public final class InfractionPlayer implements ForwardingAudience.Single {
this.username = player.getUsername();
}

/**
* Constructor of an InfractorPlayer based on its {@link UUID}
* @param uuid the uuid on which it will be based
* @throws PlayerNotAvailableException
*/
@Internal
InfractionPlayer(final @NotNull UUID uuid, final @NotNull ProxyServer proxy) throws PlayerNotAvailableException{
this.player = proxy.getPlayer(uuid).orElseThrow(PlayerNotAvailableException::new);
this.preLastMessage = " .";
this.lastMessage = " ";
this.preLastCommand = " ";
this.lastCommand = " .";
this.timeSinceLastMessage = Instant.now();
this.timeSinceLastCommand = Instant.now();
this.violationsCount = new ViolationCount();
this.isOnline = true;
this.username = player.getUsername();
}

/**
* A simple method to obtain the player's name
* @return infraction player name
Expand Down Expand Up @@ -191,19 +171,12 @@ public long getTimeSinceLastCommand(){
* @throws PlayerNotAvailableException if the player is not available
*/
public static @Nullable InfractionPlayer get(final @NotNull UUID uuid, @NotNull ProxyServer proxy) throws PlayerNotAvailableException{
InfractionPlayer player = ChatRegulator.infractionPlayers.get(Objects.requireNonNull(uuid));
if(player != null){
return player;
} else {
Optional<Player> optionalPlayer = proxy.getPlayer(uuid);
if(optionalPlayer.isPresent()){
player = InfractionPlayer.get(optionalPlayer.get());
ChatRegulator.infractionPlayers.put(uuid, player);
return player;
} else {
throw new PlayerNotAvailableException(uuid);
}
}
return ChatRegulator.infractionPlayers
.get(Objects.requireNonNull(uuid),
(id) -> new InfractionPlayer(
proxy.getPlayer(id)
.orElseThrow(() -> new PlayerNotAvailableException(id))
));
}

/**
Expand All @@ -213,21 +186,16 @@ public long getTimeSinceLastCommand(){
*/
public static @NotNull InfractionPlayer get(final @NotNull Player player){
final UUID uuid = Objects.requireNonNull(player).getUniqueId();
InfractionPlayer infractor = ChatRegulator.infractionPlayers.get(uuid);
if(infractor != null){
if(!infractor.isOnline()) {
infractor.player = player;
}
return infractor;
} else {
infractor = new InfractionPlayer(player);
ChatRegulator.infractionPlayers.put(uuid, infractor);
return infractor;
final InfractionPlayer infractor = ChatRegulator.infractionPlayers
.get(uuid, id -> new InfractionPlayer(player));
if (!infractor.isOnline()) {
infractor.player = player;
}
return infractor;
}

public static @Nullable InfractionPlayer get(final @NotNull String name){
return ChatRegulator.infractionPlayers.values().stream()
return ChatRegulator.infractionPlayers.asMap().values().stream()
.filter(p -> p.username().equalsIgnoreCase(name))
.findAny().orElse(null);
}
Expand All @@ -240,8 +208,8 @@ public boolean equals(Object o){
if(!(o instanceof final InfractionPlayer other)) {
return false;
}
return Objects.equals(other.getViolations(), this.getViolations())
|| Objects.equals(other.username, this.username);
return Objects.equals(other.username, this.username)
&& Objects.equals(other.getViolations(), this.getViolations());
}

@Override
Expand Down
Expand Up @@ -81,8 +81,8 @@ public int getCount(@NotNull InfractionType type){

@Override
public boolean equals(Object o){
if(this==o) return true;
if(!(o instanceof final ViolationCount that)) return false;
if (this==o) return true;
if (!(o instanceof final ViolationCount that)) return false;
return this.spamViolations == that.spamViolations
&& this.capsviolations == that.capsviolations
&& this.commandViolations == that.commandViolations
Expand Down
Expand Up @@ -14,7 +14,7 @@
/**
* Basis for infringement events
*/
public class ViolationEvent implements ResultedEvent<GenericResult> {
public abstract class ViolationEvent implements ResultedEvent<GenericResult> {
/**
* InfractionPlayer involved in detection
*/
Expand Down
Expand Up @@ -13,6 +13,7 @@
import me.dreamerzero.chatregulator.config.Configuration;
import me.dreamerzero.chatregulator.modules.checks.CommandCheck;
import me.dreamerzero.chatregulator.modules.checks.SyntaxCheck;
import me.dreamerzero.chatregulator.result.Result;
import me.dreamerzero.chatregulator.utils.CommandUtils;
import me.dreamerzero.chatregulator.utils.GeneralUtils.EventBundle;
import me.dreamerzero.chatregulator.wrapper.event.CommandWrapper;
Expand Down Expand Up @@ -87,7 +88,10 @@ && checkAndCall(
player,
string,
InfractionType.SYNTAX,
SyntaxCheck.createCheck(string).join(),
SyntaxCheck.createCheck(string).exceptionallyAsync(e -> {
plugin.getLogger().error("An Error ocurred on Syntax Check", e);
return new Result("", false);
}).join(),
SourceType.COMMAND
),
plugin
Expand All @@ -107,7 +111,10 @@ && checkAndCall(
player,
string,
InfractionType.BCOMMAND,
CommandCheck.createCheck(string).join(),
CommandCheck.createCheck(string).exceptionallyAsync(e -> {
plugin.getLogger().error("An Error ocurred on Blocked Commands Check", e);
return new Result("", false);
}).join(),
SourceType.COMMAND
),
plugin
Expand Down
Expand Up @@ -34,7 +34,8 @@ public EventTask onLeave(final DisconnectEvent event){

plugin.getProxy().getScheduler().buildTask(plugin, () -> {
if(plugin.getProxy().getPlayer(uuid).isEmpty()) {
plugin.getLogger().debug("The player {} was eliminated", plugin.getChatPlayers().remove(uuid).username());
plugin.getLogger().debug("The player {} was eliminated", player.username());
plugin.removePlayer(uuid);
}
}).delay(
Configuration.getConfig().getGeneralConfig().deleteUsersTime(),
Expand Down
Expand Up @@ -33,7 +33,7 @@ private CapsCheck(int limit){
*/
@Override
public CompletableFuture<Result> check(final @NotNull String string) {
return CompletableFuture.completedFuture(Objects.requireNonNull(string)
return CompletableFuture.supplyAsync(() -> Objects.requireNonNull(string)
.chars()
.filter(Character::isUpperCase)
.count() >= this.limit
Expand Down
Expand Up @@ -33,12 +33,14 @@ private CommandCheck(Collection<String> blocledCommands){
*/
@Override
public CompletableFuture<Result> check(@NotNull String string) {
for (final String blockedCommand : blockedCommands){
if(CommandUtils.isStartingString(string, blockedCommand)){
return CompletableFuture.completedFuture(new Result(string, true));
return CompletableFuture.supplyAsync(() -> {
for (final String blockedCommand : blockedCommands){
if (CommandUtils.isStartingString(string, blockedCommand)) {
return new Result(string, true);
}
}
}
return CompletableFuture.completedFuture(new Result(string, false));
return new Result(string, false);
});
}

@Override
Expand Down
Expand Up @@ -44,13 +44,15 @@ public static void setFloodRegex(){
* @return a {@link PatternReplaceableResult} with the Result of the check
*/
@Override
public CompletableFuture<Result> check(final @NotNull String string){
final Matcher matcher = realPattern.matcher(Objects.requireNonNull(string));
return CompletableFuture.completedFuture(new PatternReplaceableResult(string, matcher.find(), realPattern, matcher){
@Override
public String replaceInfraction(){
return matcher.replaceAll(match -> Character.toString(match.group().charAt(0)));
}
public CompletableFuture<Result> check(@NotNull final String string){
return CompletableFuture.supplyAsync(() -> {
final Matcher matcher = realPattern.matcher(Objects.requireNonNull(string));
return new PatternReplaceableResult(string, matcher.find(), realPattern, matcher){
@Override
public String replaceInfraction() {
return matcher.replaceAll(match -> Character.toString(match.group().charAt(0)));
}
};
});
}

Expand All @@ -67,7 +69,7 @@ public static FloodCheck.Builder builder(){
return new FloodCheck.Builder();
}

/**Floood Check Builder */
/**Flood Check Builder */
public static class Builder implements AbstractBuilder<FloodCheck> {
private Pattern pattern;

Expand Down
Expand Up @@ -20,7 +20,7 @@ public interface ICheck {
* @since 3.0.0
* @return a CompletableFuture with the result of the check
*/
@NotNull CompletableFuture<Result> check(@NotNull final String string);
@NotNull CompletableFuture<Result> check(final @NotNull String string);

/**
* Get the {@link InfractionType} of this check
Expand Down
Expand Up @@ -4,6 +4,7 @@
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.regex.MatchResult;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

Expand Down Expand Up @@ -47,31 +48,42 @@ private InfractionCheck(boolean blockable, Pattern... blockedWords){
* @see ICheck
*/
@Override
public CompletableFuture<Result> check(@NotNull final String string){
final List<Pattern> patterns = new ArrayList<>();
boolean detected = false;
for (final Pattern pattern : blockedWords) {
final Matcher match = pattern.matcher(string);
if(match.find()){
detected = true;
if(blockable) {
return CompletableFuture.completedFuture(new PatternResult(match.group(), true, pattern, match));
public CompletableFuture<Result> check(final @NotNull String string){
return CompletableFuture.supplyAsync(() -> {
final List<Pattern> patterns = new ArrayList<>();
boolean detected = false;
for (final Pattern pattern : blockedWords) {
final Matcher match = pattern.matcher(string);
if(match.find()){
detected = true;
if (blockable) {
return new PatternResult(match.group(), blockable, pattern, match);
}
patterns.add(pattern);
}
patterns.add(pattern);
}
}
return CompletableFuture.completedFuture(detected
? new ReplaceableResult(patterns.toString(), true){
@Override
public String replaceInfraction(){
String original = string;
for(Pattern pattern : patterns){
original = pattern.matcher(original).replaceAll("***");
return detected
? new ReplaceableResult(patterns.toString(), true){
@Override
public String replaceInfraction(){
String original = string;
for (final Pattern pattern : patterns) {
original = pattern.matcher(original).replaceAll(InfractionCheck::generateReplacement);
}
return original;
}
return original;
}
}
: new Result(string, false));
: new Result(string, false);
});
}

private static String generateReplacement(MatchResult result) {
final int size = result.group().length()/2;
final StringBuilder builder = new StringBuilder(size);
for (int i = 0; i < size; i++) {
builder.append('*');
}
return builder.toString();
}

@Override
Expand Down
Expand Up @@ -28,8 +28,9 @@ private SpamCheck(@NotNull InfractionPlayer infractionPlayer, @NotNull SourceTyp
*/
@Override
public CompletableFuture<Result> check(final @NotNull String string){
final boolean infricted = this.spamInfricted(Objects.requireNonNull(string));
return CompletableFuture.completedFuture(new Result(string, infricted));
return CompletableFuture.supplyAsync(
() -> new Result(string, this.spamInfricted(Objects.requireNonNull(string)))
);
}

/**
Expand Down
Expand Up @@ -19,8 +19,10 @@ public final class SyntaxCheck implements ICheck{
*/
@Override
public CompletableFuture<Result> check(final @NotNull String string) {
final String command = CommandUtils.getFirstArgument(Objects.requireNonNull(string));
return CompletableFuture.completedFuture(new Result(command, command.indexOf(':') != -1));
return CompletableFuture.supplyAsync(() -> {
final String command = CommandUtils.getFirstArgument(Objects.requireNonNull(string));
return new Result(command, command.indexOf(':') != -1);
});
}

@Override
Expand Down

0 comments on commit 32978c2

Please sign in to comment.