From 4b6c5beefd555ea0bfded31d727d1a0f5743d06c Mon Sep 17 00:00:00 2001 From: Richard Date: Sun, 16 Feb 2020 21:33:08 +0100 Subject: [PATCH] Fixed a few minor issues --- src/bungee.yml | 2 +- src/config.yml | 43 ++++- .../jpx3/ips/config/ConfigurationService.java | 71 +++++++- .../ips/connect/bukkit/MessengerService.java | 5 +- .../ips/connect/bukkit/PacketReceiver.java | 27 +-- .../jpx3/ips/connect/bukkit/PacketSender.java | 3 +- ...tSubscriber.java => PacketSubscriber.java} | 2 +- .../bukkit/PacketSubscriptionService.java | 11 +- .../connect/database/AsyncQueryExecutor.java | 37 ++-- .../ips/connect/database/DatabaseService.java | 2 +- .../ips/connect/database/IQueryExecutor.java | 2 + src/de/jpx3/ips/punish/BanEntry.java | 8 + src/de/jpx3/ips/punish/MessageFormatter.java | 167 ++++++++++++++++++ ...hmentDriver.java => PunishmentDriver.java} | 2 +- src/de/jpx3/ips/punish/PunishmentService.java | 24 ++- .../punish/driver/RemotePunishmentDriver.java | 135 +++++++++----- .../driver/RuntimePunishmentDriver.java | 51 ++++-- 17 files changed, 477 insertions(+), 115 deletions(-) rename src/de/jpx3/ips/connect/bukkit/{IPacketSubscriber.java => PacketSubscriber.java} (68%) create mode 100644 src/de/jpx3/ips/punish/MessageFormatter.java rename src/de/jpx3/ips/punish/{IPunishmentDriver.java => PunishmentDriver.java} (86%) diff --git a/src/bungee.yml b/src/bungee.yml index ba2a898..6cc6e7e 100644 --- a/src/bungee.yml +++ b/src/bungee.yml @@ -1,6 +1,6 @@ name: IntaveProxySupport author: Jpx3 description: Proxy support for Intave AntiCheat. Made with - not only but mostly - my keyboard and some love. -version: 0.1.6 +version: 0.9.2 main: de.jpx3.ips.IntaveProxySupportPlugin \ No newline at end of file diff --git a/src/config.yml b/src/config.yml index cb31b2a..caa1a5d 100644 --- a/src/config.yml +++ b/src/config.yml @@ -1,27 +1,27 @@ ### ### -## Intave Proxy Support 0.1.6 ## +## Intave Proxy Support 0.9.2 ## ## by Jpx3 ## ### ### # Connections connection: - # Connection between proxy and the database. + # Connection between proxy and database. sql: enabled: false connection: jdbc-service: "mysql" - host: "a.a.a.a.a.a.org" + host: "ich.bin.net" port: -1 - database: "thetabledancingbar" - user: "XxX$$rIcHy$$XxX" - password: "1234" + database: "tabledance24" + user: "XxX$$R_I_C_H_Y$$XxX" + password: "12345678" create-tables: true - # Connection between proxy and bukkit. + # Connection between our proxy and bukkit (where Intave is running). bukkit: enabled: true @@ -32,4 +32,31 @@ punishment: # SQL | Punishments are saved in a database and cached # SQL-NC | Punishments are saved in a database and are not cached # NONE - driver: "RUNTIME" \ No newline at end of file + driver: "RUNTIME" + + # Message layout + # + # Please note that this is not yet working in version 0.9.2 + # + # {expire-short} - Time until expiration (format-example: "13m 23d 13h 22m 19s" or "never") + # {expire} - Time until expiration with full annotations (format-example: "13 months, 23 days, 13 hours, 22 minutes & 19 seconds" or "never") + # {reason} - Entered reason for punishment + message-layout: + + kick-layout: | + &4&lYou have been kicked.&r&r + + &fReason: &b&l{reason}&r&r&r + + &r&cPlease contact our staff in case&r&r + &cyou have any questions regarding this action.&r + + ban-layout: | + &4&lYou have been banned.&r&r + + &fReason: &b&l{reason}&r&r&r + &fExpires: &b&l{expire-short}&r&r&r + + &r&cPlease contact our staff in case&r&r + &cyou have any questions regarding this action.&r + diff --git a/src/de/jpx3/ips/config/ConfigurationService.java b/src/de/jpx3/ips/config/ConfigurationService.java index a27b911..bd0a1de 100644 --- a/src/de/jpx3/ips/config/ConfigurationService.java +++ b/src/de/jpx3/ips/config/ConfigurationService.java @@ -1,13 +1,13 @@ package de.jpx3.ips.config; import com.google.common.base.Preconditions; +import com.google.common.io.ByteStreams; import net.md_5.bungee.api.plugin.Plugin; import net.md_5.bungee.config.Configuration; import net.md_5.bungee.config.ConfigurationProvider; import net.md_5.bungee.config.YamlConfiguration; -import java.io.File; -import java.io.IOException; +import java.io.*; public final class ConfigurationService { private final Configuration configuration; @@ -20,13 +20,23 @@ public Configuration configuration() { return configuration; } + private final static String CONFIGURATION_NAME = "config.yml"; + private final static String DATAFOLDER_CREATION_ERROR = "Unable to create data folder"; + private final static String CONFIGURATION_CREATION_ERROR = "Unable to create configuration file"; + public static ConfigurationService createFrom(Plugin plugin) { Preconditions.checkNotNull(plugin); ConfigurationProvider configurationProvider = ConfigurationProvider.getProvider(YamlConfiguration.class); - File configurationFile - = new File(plugin.getDataFolder(), "config.yml"); + + File dataFolder = plugin.getDataFolder(); + File configurationFile = new File(dataFolder, CONFIGURATION_NAME); + + ensureConfigurationExistence( + dataFolder, + configurationFile + ); Configuration configuration; try { @@ -37,4 +47,57 @@ public static ConfigurationService createFrom(Plugin plugin) { return new ConfigurationService(configuration); } + + private static void ensureConfigurationExistence(File dataFolder, + File configurationFile + ) { + if(!dataFolder.exists()) { + if(!dataFolder.mkdir()) { + System.out.println(CONFIGURATION_CREATION_ERROR); + } + } + + if(!configurationFile.exists()) { + try { + configurationFile.createNewFile(); + + moveResourceToFile( + CONFIGURATION_NAME, + configurationFile + ); + + } catch (IOException e) { + throw new IllegalStateException(DATAFOLDER_CREATION_ERROR, e); + } + } + } + + private final static String RESOURCE_MOVE_TO_FILE_ERROR_LAYOUT = "Unable to move resource %s to %s"; + + private static void moveResourceToFile(String resource, + File outputFile + ) { + try { + ClassLoader classLoader = + ConfigurationService.class.getClassLoader(); + try (InputStream inputStream = + classLoader.getResourceAsStream(resource); + OutputStream outputStream = + new FileOutputStream(outputFile)) { + + ByteStreams.copy(inputStream, outputStream); + } + } catch (IOException e) { + String errorMessage = String.format( + RESOURCE_MOVE_TO_FILE_ERROR_LAYOUT, + resource, + outputFile.getAbsolutePath() + ); + + throw new IllegalStateException( + errorMessage, + e + ); + } + } } diff --git a/src/de/jpx3/ips/connect/bukkit/MessengerService.java b/src/de/jpx3/ips/connect/bukkit/MessengerService.java index 8fb7ab0..f9c23af 100644 --- a/src/de/jpx3/ips/connect/bukkit/MessengerService.java +++ b/src/de/jpx3/ips/connect/bukkit/MessengerService.java @@ -5,9 +5,8 @@ import net.md_5.bungee.config.Configuration; public final class MessengerService { - public final static int PROTOCOL_VERSION = 2; - public final static String INCOMING_CHANNEL = "ipc-s2p"; - public final static String OUTGOING_CHANNEL = "ipc-p2s"; + public final static int PROTOCOL_VERSION = 3; + public final static String OUTGOING_CHANNEL = "IPC-P2S"; public final static String PROTOCOL_HEADER = "IPC_BEGIN"; public final static String PROTOCOL_FOOTER = "IPC_END"; diff --git a/src/de/jpx3/ips/connect/bukkit/PacketReceiver.java b/src/de/jpx3/ips/connect/bukkit/PacketReceiver.java index 6f3b704..3c97b69 100644 --- a/src/de/jpx3/ips/connect/bukkit/PacketReceiver.java +++ b/src/de/jpx3/ips/connect/bukkit/PacketReceiver.java @@ -34,25 +34,25 @@ public void unset() { @SuppressWarnings("unused") @EventHandler(priority = EventPriority.LOWEST) public void onPluginMessageReceive(PluginMessageEvent event) { - if (isUpstream(event.getSender()) || - !isMarkedAsIntaveChannel(event.getTag()) - ) { + if (isUpstream(event.getSender())) { return; } - event.setCancelled(true); - receivePayloadPacket((UserConnection) event.getReceiver(), event.getData()); + boolean isIntavePacket = receivePayloadPacket((UserConnection) event.getReceiver(), event.getData()); + + if(isIntavePacket) { + event.setCancelled(true); + } } - public void receivePayloadPacket(UserConnection player, - byte[] data + public boolean receivePayloadPacket(UserConnection player, + byte[] data ) { ByteArrayDataInput inputData = newByteArrayDataInputFrom(data); try { - String channelName = readChannelName(inputData); if (!channelName.equalsIgnoreCase(PROTOCOL_HEADER)) { - return; + return false; } int protocolVersion = readProtocolVersion(inputData); @@ -80,7 +80,11 @@ public void receivePayloadPacket(UserConnection player, player, constructedPacket ); - } catch (Exception exception) { + + return true; + } catch (IllegalStateException exception) { + return false; + } catch (IllegalAccessException | InstantiationException exception) { throw new IllegalStateException("Could not handle incoming packet", exception); } } @@ -128,8 +132,7 @@ private ByteArrayDataInput newByteArrayDataInputFrom(byte[] byteArray) { } private boolean isMarkedAsIntaveChannel(String channelTag) { - return channelTag.equalsIgnoreCase(INCOMING_CHANNEL) || - channelTag.equalsIgnoreCase(OUTGOING_CHANNEL); + return channelTag.equalsIgnoreCase(OUTGOING_CHANNEL); } private boolean isUpstream(Connection connection) { diff --git a/src/de/jpx3/ips/connect/bukkit/PacketSender.java b/src/de/jpx3/ips/connect/bukkit/PacketSender.java index 30b8d81..c8a3bd2 100644 --- a/src/de/jpx3/ips/connect/bukkit/PacketSender.java +++ b/src/de/jpx3/ips/connect/bukkit/PacketSender.java @@ -76,8 +76,7 @@ private void pushPacketData( } private byte[] serialize(AbstractPacket packet) { - //noinspection UnstableApiUsage - ByteArrayDataOutput dataOutput = ByteStreams.newDataOutput(); + ByteArrayDataOutput dataOutput = newByteArrayDataOutput(); packet.applyTo(dataOutput); return dataOutput.toByteArray(); } diff --git a/src/de/jpx3/ips/connect/bukkit/IPacketSubscriber.java b/src/de/jpx3/ips/connect/bukkit/PacketSubscriber.java similarity index 68% rename from src/de/jpx3/ips/connect/bukkit/IPacketSubscriber.java rename to src/de/jpx3/ips/connect/bukkit/PacketSubscriber.java index 2c947ef..3ef148e 100644 --- a/src/de/jpx3/ips/connect/bukkit/IPacketSubscriber.java +++ b/src/de/jpx3/ips/connect/bukkit/PacketSubscriber.java @@ -2,6 +2,6 @@ import net.md_5.bungee.api.connection.ProxiedPlayer; -public interface IPacketSubscriber

{ +public interface PacketSubscriber

{ void handle(ProxiedPlayer sender, P packet); } diff --git a/src/de/jpx3/ips/connect/bukkit/PacketSubscriptionService.java b/src/de/jpx3/ips/connect/bukkit/PacketSubscriptionService.java index f49cfb3..be29e14 100644 --- a/src/de/jpx3/ips/connect/bukkit/PacketSubscriptionService.java +++ b/src/de/jpx3/ips/connect/bukkit/PacketSubscriptionService.java @@ -1,6 +1,7 @@ package de.jpx3.ips.connect.bukkit; import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import de.jpx3.ips.IntaveProxySupportPlugin; @@ -12,7 +13,7 @@ @SuppressWarnings({"rawtypes", "unchecked"}) public final class PacketSubscriptionService { private IntaveProxySupportPlugin plugin; - private Map, List> packetSubscriptions; + private Map, List> packetSubscriptions = ImmutableMap.of(); private PacketSubscriptionService(IntaveProxySupportPlugin plugin) { this.plugin = plugin; @@ -33,7 +34,7 @@ public void reset() { public

void addSubscriber( Class

type, - IPacketSubscriber

subscriber + PacketSubscriber

subscriber ) { Preconditions.checkNotNull(type); Preconditions.checkNotNull(subscriber); @@ -53,15 +54,15 @@ public

void broadcastPacketToSubscribers( packetSubscriber.handle(sender, packet)); } - private List subscriptionsOf(AbstractPacket packet) { + private List subscriptionsOf(AbstractPacket packet) { return subscriptionsOf(packet.getClass()); } - private List subscriptionsOf(Class packetClass) { + private List subscriptionsOf(Class packetClass) { return packetSubscriptions().get(packetClass); } - public Map, List> packetSubscriptions() { + public Map, List> packetSubscriptions() { return packetSubscriptions; } diff --git a/src/de/jpx3/ips/connect/database/AsyncQueryExecutor.java b/src/de/jpx3/ips/connect/database/AsyncQueryExecutor.java index ffa7798..a60b116 100644 --- a/src/de/jpx3/ips/connect/database/AsyncQueryExecutor.java +++ b/src/de/jpx3/ips/connect/database/AsyncQueryExecutor.java @@ -31,13 +31,16 @@ public void update(String query) { Preconditions.checkNotNull(query); ensureStatementPresence(); - pushToExecutor(() -> { - try { - statement.execute(query); - } catch (SQLException e) { - e.printStackTrace(); - } - }); + pushToExecutor(() -> updateBlocking(query)); + } + + @Override + public void updateBlocking(String query) { + try { + statement.execute(query); + } catch (SQLException e) { + throw new IllegalStateException(e); + } } @Override @@ -49,15 +52,23 @@ public void find(String query, ensureStatementPresence(); pushToExecutor(() -> { - try { - ResultSet resultSet = statement.executeQuery(query); - lazyReturn.accept(asTableData(resultSet)); - } catch (SQLException e) { - e.printStackTrace(); - } + lazyReturn.accept(findBlocking(query)); }); } + @Override + public List> findBlocking(String query) { + Preconditions.checkNotNull(query); + ensureStatementPresence(); + + try { + ResultSet resultSet = statement.executeQuery(query); + return asTableData(resultSet); + } catch (SQLException e) { + throw new IllegalStateException(e); + } + } + private void pushToExecutor(Runnable runnable) { Preconditions.checkNotNull(runnable); diff --git a/src/de/jpx3/ips/connect/database/DatabaseService.java b/src/de/jpx3/ips/connect/database/DatabaseService.java index 6ac365d..1d4f590 100644 --- a/src/de/jpx3/ips/connect/database/DatabaseService.java +++ b/src/de/jpx3/ips/connect/database/DatabaseService.java @@ -10,7 +10,7 @@ import java.util.concurrent.Executor; public final class DatabaseService { - private static final String CONNECTION_URL_LAYOUT = "jdbc:%s://%s:%s;databaseName=%s;user=%s;password=%s?autoReconnect=true"; + private static final String CONNECTION_URL_LAYOUT = "jdbc:%s://%s:%s/%s?user=%s&password=%s&autoReconnect=true"; private final IntaveProxySupportPlugin plugin; private final Configuration configuration; diff --git a/src/de/jpx3/ips/connect/database/IQueryExecutor.java b/src/de/jpx3/ips/connect/database/IQueryExecutor.java index a1ea6f2..562c615 100644 --- a/src/de/jpx3/ips/connect/database/IQueryExecutor.java +++ b/src/de/jpx3/ips/connect/database/IQueryExecutor.java @@ -6,5 +6,7 @@ public interface IQueryExecutor { void update(String query); + void updateBlocking(String query); void find(String query, Consumer>> lazyReturn); + List> findBlocking(String query); } diff --git a/src/de/jpx3/ips/punish/BanEntry.java b/src/de/jpx3/ips/punish/BanEntry.java index 722ec4b..e7f0ec1 100644 --- a/src/de/jpx3/ips/punish/BanEntry.java +++ b/src/de/jpx3/ips/punish/BanEntry.java @@ -43,6 +43,14 @@ public boolean expired() { return end < System.currentTimeMillis(); } + public String toString() { + return "BanEntry{" + + "id=" + id + + ", reason='" + reason + '\'' + + ", end=" + end + + '}'; + } + public static final class Builder { private UUID id; private String reason; diff --git a/src/de/jpx3/ips/punish/MessageFormatter.java b/src/de/jpx3/ips/punish/MessageFormatter.java new file mode 100644 index 0000000..5e383b1 --- /dev/null +++ b/src/de/jpx3/ips/punish/MessageFormatter.java @@ -0,0 +1,167 @@ +package de.jpx3.ips.punish; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import net.md_5.bungee.api.ChatColor; + +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; + +public final class MessageFormatter { + public static String formatMessage(String layout, + BanEntry banEntry + ) { + Preconditions.checkNotNull(layout); + + Map replacementMapping = + banEntry == null ? ImmutableMap.of() : prepareMapping(banEntry); + + String formattedMessage = replaceKeys(layout, replacementMapping); + return translateColorCodes(formattedMessage); + } + + private static Map prepareMapping(BanEntry entry) { + Map replacements = + Maps.newHashMap(); + + String entryReason = entry.reason(); + long entryDurationInMilliSeconds = + entry.ending() - System.currentTimeMillis(); + long entryDurationInSeconds = + TimeUnit.MILLISECONDS.toSeconds(entryDurationInMilliSeconds); + + String formattedEntryDuration = formatDurationFrom( + TimeUnitTypeNameResolver.FULL, + ", ", + entryDurationInSeconds + ); + + String formattedEntryDurationShort = formatDurationFrom( + TimeUnitTypeNameResolver.SHORTED, + " ", + entryDurationInSeconds + ); + + replacements.put("reason", entryReason); + replacements.put("expire", formattedEntryDuration); + replacements.put("expire-short", formattedEntryDurationShort); + + return replacements; + } + + private final static String REGEX_FORMATTED_OPENING_CURLY_BRACE = "\\{"; + private final static String REGEX_FORMATTED_CLOSING_CURLY_BRACE = "}"; + + private static String replaceKeys(String layout, + Map keyToReplacement + ) { + for ( + Map.Entry keyToReplacementEntry : + keyToReplacement.entrySet() + ) { + String key = keyToReplacementEntry.getKey(); + String replacement = keyToReplacementEntry.getValue(); + + String keyWrappedInCurlyBraces = + REGEX_FORMATTED_OPENING_CURLY_BRACE + + key + + REGEX_FORMATTED_CLOSING_CURLY_BRACE; + + layout = layout.replaceAll(keyWrappedInCurlyBraces, replacement); + } + + return layout; + } + + private static String translateColorCodes(String input) { + return ChatColor.translateAlternateColorCodes('&', input); + } + + private final static List WEIGHT_ORDERED_TIME_UNITS = + Lists.newLinkedList(); + private final static long SECONDS_IN_A_HUNDRED_YEARS = + TimeUnit.DAYS.toSeconds(365 * 100); + private final static String WILL_NOT_EXPIRE_EXPRESSION = + "Never"; + + private static String formatDurationFrom(TimeUnitTypeNameResolver nameResolver, + String spliterator, + long timeInSeconds + ) { + StringBuilder resultBuilder = new StringBuilder(); + + if(timeInSeconds > SECONDS_IN_A_HUNDRED_YEARS) { + resultBuilder.append(WILL_NOT_EXPIRE_EXPRESSION); + return resultBuilder.toString(); + } + + for (TimeUnit timeUnit : WEIGHT_ORDERED_TIME_UNITS) { + String timeUnitName = unitNameOf(timeUnit, nameResolver); + long unitInSeconds = secondsOf(timeUnit); + long fittingUnitAmount = timeInSeconds / unitInSeconds; + + fittingUnitAmount = Math.min(99, fittingUnitAmount); + + if(fittingUnitAmount > 1) { + resultBuilder + .append(String.format("%02d", fittingUnitAmount)) + .append(timeUnitName); + timeInSeconds -= fittingUnitAmount * unitInSeconds; + + if(timeInSeconds >= 1) { + resultBuilder.append(spliterator); + } + } + } + + return resultBuilder.toString(); + } + + private static String unitNameOf(TimeUnit timeUnit, + TimeUnitTypeNameResolver nameResolver + ) { + return nameResolver.nameBy(timeUnit); + } + + private static boolean timeUnitInvalid(TimeUnit unit) { + return secondsOf(unit) < 1; + } + + private static long secondsOf(TimeUnit unit) { + return unit.toSeconds(1); + } + + static { + List timeUnits = Lists.newArrayList(Arrays.asList(TimeUnit.values())); + timeUnits.removeIf(MessageFormatter::timeUnitInvalid); + timeUnits.sort( + Comparator + .comparing(MessageFormatter::secondsOf) + .reversed() + ); + WEIGHT_ORDERED_TIME_UNITS.addAll(timeUnits); + } + + public enum TimeUnitTypeNameResolver { + FULL(timeUnit -> + " " + timeUnit.name().toLowerCase()), + SHORTED(timeUnit -> + String.valueOf(timeUnit.name().charAt(0)).toLowerCase()); + + private Function mapper; + + TimeUnitTypeNameResolver(Function mapper) { + this.mapper = mapper; + } + + private String nameBy(TimeUnit unit) { + return mapper.apply(unit); + } + } +} diff --git a/src/de/jpx3/ips/punish/IPunishmentDriver.java b/src/de/jpx3/ips/punish/PunishmentDriver.java similarity index 86% rename from src/de/jpx3/ips/punish/IPunishmentDriver.java rename to src/de/jpx3/ips/punish/PunishmentDriver.java index abb10d3..bac8144 100644 --- a/src/de/jpx3/ips/punish/IPunishmentDriver.java +++ b/src/de/jpx3/ips/punish/PunishmentDriver.java @@ -2,7 +2,7 @@ import java.util.UUID; -public interface IPunishmentDriver { +public interface PunishmentDriver { void kickPlayer(UUID id, String kickMessage); void banPlayerTemporarily(UUID id, long endOfBanTimestamp, String banMessage); void banPlayer(UUID id, String banMessage); diff --git a/src/de/jpx3/ips/punish/PunishmentService.java b/src/de/jpx3/ips/punish/PunishmentService.java index 0f10a2d..edf380b 100644 --- a/src/de/jpx3/ips/punish/PunishmentService.java +++ b/src/de/jpx3/ips/punish/PunishmentService.java @@ -14,7 +14,10 @@ public final class PunishmentService { private final IntaveProxySupportPlugin plugin; private final Configuration configuration; - private IPunishmentDriver punishmentDriver; + public final static String BAN_LAYOUT_CONFIGURATION_KEY = "message-layout.ban-layout"; + public final static String KICK_LAYOUT_CONFIGURATION_KEY = "message-layout.kick-layout"; + + private PunishmentDriver punishmentDriver; private PunishmentService(IntaveProxySupportPlugin plugin, Configuration configuration @@ -43,6 +46,10 @@ private void processPunishmentPacket(ProxiedPlayer sender, UUID id = packet.id(); String message = packet.message(); + if(message.length() > 64) { + message = message.substring(0, 64); + } + switch (packet.punishmentType()) { case BAN: punishmentDriver. @@ -68,10 +75,10 @@ private void setupPunishmentDriver() { private final static String DRIVER_NAME_SQL_CACHED = "sql"; private final static String DRIVER_NAME_SQL_NOCACHE = "sql-nc"; - private IPunishmentDriver loadDriverFrom(String driverName) { + private PunishmentDriver loadDriverFrom(String driverName) { Preconditions.checkNotNull(driverName); - IPunishmentDriver punishmentDriver; + PunishmentDriver punishmentDriver; switch (driverName.toLowerCase()) { case DRIVER_NAME_RUNTIME: @@ -91,7 +98,14 @@ private IPunishmentDriver loadDriverFrom(String driverName) { return punishmentDriver; } - public IPunishmentDriver punishmentDriver() { + public String resolveMessageBy(String configurationKey, + BanEntry banEntry + ) { + String layout = configuration.getString(configurationKey); + return MessageFormatter.formatMessage(layout, banEntry); + } + + public PunishmentDriver punishmentDriver() { return punishmentDriver; } @@ -99,7 +113,7 @@ public String desiredPunishmentDriverName() { return configuration.getString("driver", "runtime"); } - public void setPunishmentDriver(IPunishmentDriver punishmentDriver) { + public void setPunishmentDriver(PunishmentDriver punishmentDriver) { this.punishmentDriver = punishmentDriver; } diff --git a/src/de/jpx3/ips/punish/driver/RemotePunishmentDriver.java b/src/de/jpx3/ips/punish/driver/RemotePunishmentDriver.java index e35a404..7cb2b94 100644 --- a/src/de/jpx3/ips/punish/driver/RemotePunishmentDriver.java +++ b/src/de/jpx3/ips/punish/driver/RemotePunishmentDriver.java @@ -1,13 +1,15 @@ package de.jpx3.ips.punish.driver; import com.google.common.base.Preconditions; -import com.google.common.collect.Maps; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; import de.jpx3.ips.IntaveProxySupportPlugin; import de.jpx3.ips.connect.database.DatabaseService; import de.jpx3.ips.punish.BanEntry; -import de.jpx3.ips.punish.IPunishmentDriver; +import de.jpx3.ips.punish.PunishmentDriver; +import de.jpx3.ips.punish.PunishmentService; import net.md_5.bungee.api.connection.ProxiedPlayer; -import net.md_5.bungee.api.event.PostLoginEvent; +import net.md_5.bungee.api.event.LoginEvent; import net.md_5.bungee.api.plugin.Listener; import net.md_5.bungee.event.EventHandler; @@ -15,17 +17,19 @@ import java.util.Map; import java.util.Optional; import java.util.UUID; +import java.util.concurrent.TimeUnit; import java.util.function.Consumer; -public final class RemotePunishmentDriver implements IPunishmentDriver, Listener { +@SuppressWarnings("UnstableApiUsage") +public final class RemotePunishmentDriver implements PunishmentDriver, Listener { private final static String TABLE_NAME = "ips_ban_entries"; - private final static String TABLE_SETUP_QUERY = "create table if not exists `%s`.`"+TABLE_NAME+"` ( `EntryId` INT NOT NULL AUTO_INCREMENT ,`UniquePlayerId` VARCHAR(36) NOT NULL ,`BanExpireTimestamp` BIGINT NOT NULL ,`BanReason` VARCHAR NOT NULL ,PRIMARY KEY (`EntryId`)) ENGINE = InnoDB;"; + private final static String TABLE_SETUP_QUERY = "CREATE TABLE IF NOT EXISTS `%s`.`"+TABLE_NAME+"` ( `EntryId` INT NOT NULL AUTO_INCREMENT , `UniquePlayerId` VARCHAR(36) NOT NULL , `BanExpireTimestamp` BIGINT NOT NULL , `BanReason` VARCHAR(128) NOT NULL , PRIMARY KEY (`EntryId`)) ENGINE = InnoDB;"; private final static String SELECTION_QUERY = "select * from `"+TABLE_NAME+"` where `"+TABLE_NAME+"`.`UniquePlayerId` = \"%s\""; private final static String INSERTION_QUERY = "insert into `"+TABLE_NAME+"` (`EntryId`, `UniquePlayerId`, `BanExpireTimestamp`, `BanReason`) values (NULL, \"%s\", \"%s\", \"%s\")"; - private final static String DENY_LOGIN_MESSAGE_PREFIX = "[Intave] "; private IntaveProxySupportPlugin plugin; - private Map playerBanCache = Maps.newConcurrentMap(); + private Cache playerBanCache; + private DatabaseService service; private final boolean useCaches; @@ -43,6 +47,13 @@ public void registerEvents() { .registerListener(plugin, this); } + public void initializeCache() { + playerBanCache = CacheBuilder + .newBuilder() + .expireAfterWrite(2, TimeUnit.HOURS) + .build(); + } + public void setupTableData() { if(service.shouldCreateTables()) { String tableCreationQuery = String.format( @@ -54,13 +65,18 @@ public void setupTableData() { } @EventHandler - public void onPlayerLogin(PostLoginEvent postLoginEvent) { - resolveBanInfo(postLoginEvent.getPlayer(), banEntry -> { - if (banEntry != null && !banEntry.expired()) { - String denyReason = DENY_LOGIN_MESSAGE_PREFIX + banEntry.reason(); - postLoginEvent.getPlayer().disconnect(denyReason); - } - }); + public void onPlayerLogin(LoginEvent loginEvent) { + BanEntry banEntry = resolveNullableBanInfoBlocking( + loginEvent.getConnection().getUniqueId() + ); + if (banEntry != null && !banEntry.expired()) { + String formattedMessage = formatMessageBy( + PunishmentService.BAN_LAYOUT_CONFIGURATION_KEY, + banEntry + ); + loginEvent.setCancelled(true); + loginEvent.setCancelReason(formattedMessage); + } } @Override @@ -72,11 +88,19 @@ public void kickPlayer(UUID id, String kickMessage) { if (player == null) { return; } - player.disconnect(DENY_LOGIN_MESSAGE_PREFIX + kickMessage); + String formattedMessage = formatMessageBy( + PunishmentService.KICK_LAYOUT_CONFIGURATION_KEY, + null + ); + + player.disconnect(formattedMessage); } @Override - public void banPlayerTemporarily(UUID id, long endOfBanTimestamp, String banMessage) { + public void banPlayerTemporarily(UUID id, + long endOfBanTimestamp, + String banMessage + ) { Preconditions.checkNotNull(id); Preconditions.checkNotNull(banMessage); @@ -91,6 +115,13 @@ public void banPlayerTemporarily(UUID id, long endOfBanTimestamp, String banMess .withReason(banMessage) .build(); activateBan(banEntry); + + String formattedMessage = formatMessageBy( + PunishmentService.BAN_LAYOUT_CONFIGURATION_KEY, + banEntry + ); + + player.disconnect(formattedMessage); } @Override @@ -109,6 +140,13 @@ public void banPlayer(UUID id, String banMessage) { .withAnInfiniteDuration() .build(); activateBan(banEntry); + + String formattedMessage = formatMessageBy( + PunishmentService.BAN_LAYOUT_CONFIGURATION_KEY, + banEntry + ); + + player.disconnect(formattedMessage); } private void activateBan(BanEntry banEntry) { @@ -129,34 +167,31 @@ private void activateBan(BanEntry banEntry) { updateQuery(formattedInsertionQuery); } - private void resolveBanInfo(ProxiedPlayer proxiedPlayer, - Consumer lazyReturn - ) { - Preconditions.checkNotNull(proxiedPlayer); - Preconditions.checkNotNull(lazyReturn); - - UUID id = proxiedPlayer.getUniqueId(); + private BanEntry resolveNullableBanInfoBlocking(UUID id) { + Preconditions.checkNotNull(id); if (useCaches() && isInCache(id)) { - lazyReturn.accept(getFromCache(id)); - return; + return getFromCache(id); } String queryString = String.format(SELECTION_QUERY, id.toString()); - findByQuery(queryString, mappedResult -> { - Optional banSearch = searchActiveBan(id, mappedResult); - if (!banSearch.isPresent()) { - return; - } - BanEntry banEntry = banSearch.get(); - if (banEntry.expired()) { - return; - } - if (useCaches()) { - setInCache(id, banEntry); - } - lazyReturn.accept(banEntry); - }); + List> mappedResult = findBlockingByQuery(queryString); + Optional banSearch = searchActiveBan(id, mappedResult); + + if (!banSearch.isPresent()) { + return null; + } + + BanEntry banEntry = banSearch.get(); + if (banEntry.expired()) { + return null; + } + + if (useCaches()) { + setInCache(id, banEntry); + } + + return banEntry; } private final static String COLUMN_NAME_EXPIRATION = "BanExpireTimestamp"; @@ -190,22 +225,26 @@ private void findByQuery(String searchCommand, service.getQueryExecutor().find(searchCommand, lazyReturn); } + private List> findBlockingByQuery(String searchCommand) { + return service.getQueryExecutor().findBlocking(searchCommand); + } + private boolean entryHasExpired(long entryEnd) { return System.currentTimeMillis() > entryEnd; } + private boolean isInCache(UUID id) { + return getFromCache(id)!= null; + } + private BanEntry getFromCache(UUID id) { - return playerBanCache.get(id); + return playerBanCache.getIfPresent(id); } private void setInCache(UUID id, BanEntry banEntry) { playerBanCache.put(id, banEntry); } - private boolean isInCache(UUID id) { - return playerBanCache.containsKey(id); - } - private boolean useCaches() { return useCaches; } @@ -214,10 +253,17 @@ private ProxiedPlayer getPlayerFrom(UUID uuid) { return plugin.getProxy().getPlayer(uuid); } + private String formatMessageBy(String configurationKey, BanEntry banEntry) { + return plugin + .punishmentService() + .resolveMessageBy(configurationKey, banEntry); + } + public static RemotePunishmentDriver createWithCachingEnabled(IntaveProxySupportPlugin plugin) { RemotePunishmentDriver driver = new RemotePunishmentDriver(plugin, true); driver.setupTableData(); driver.registerEvents(); + driver.initializeCache(); return driver; } @@ -225,6 +271,7 @@ public static RemotePunishmentDriver createWithCachingDisabled(IntaveProxySuppor RemotePunishmentDriver driver = new RemotePunishmentDriver(plugin, false); driver.setupTableData(); driver.registerEvents(); + driver.initializeCache(); return driver; } } diff --git a/src/de/jpx3/ips/punish/driver/RuntimePunishmentDriver.java b/src/de/jpx3/ips/punish/driver/RuntimePunishmentDriver.java index 85f172e..59b5b2e 100644 --- a/src/de/jpx3/ips/punish/driver/RuntimePunishmentDriver.java +++ b/src/de/jpx3/ips/punish/driver/RuntimePunishmentDriver.java @@ -4,19 +4,18 @@ import com.google.common.collect.Maps; import de.jpx3.ips.IntaveProxySupportPlugin; import de.jpx3.ips.punish.BanEntry; -import de.jpx3.ips.punish.IPunishmentDriver; +import de.jpx3.ips.punish.PunishmentDriver; +import de.jpx3.ips.punish.PunishmentService; import net.md_5.bungee.api.connection.PendingConnection; import net.md_5.bungee.api.connection.ProxiedPlayer; -import net.md_5.bungee.api.event.PreLoginEvent; +import net.md_5.bungee.api.event.LoginEvent; import net.md_5.bungee.api.plugin.Listener; import net.md_5.bungee.event.EventHandler; import java.util.Map; import java.util.UUID; -public final class RuntimePunishmentDriver implements IPunishmentDriver, Listener { - private final static String DENY_LOGIN_MESSAGE_PREFIX = "[Intave] "; - +public final class RuntimePunishmentDriver implements PunishmentDriver, Listener { private final Map bannedPlayers = Maps.newHashMap(); private final IntaveProxySupportPlugin plugin; @@ -31,15 +30,19 @@ public void registerEvents() { } @EventHandler - public void onPlayerLogin(PreLoginEvent preLoginEvent) { - PendingConnection connection = preLoginEvent.getConnection(); + public void onPlayerLogin(LoginEvent loginEvent) { + PendingConnection connection = loginEvent.getConnection(); UUID playerId = connection.getUniqueId(); if (bannedPlayers.containsKey(playerId)) { BanEntry banEntry = bannedPlayers.get(playerId); if (!banEntry.expired()) { - String banReason = banEntry.reason(); - preLoginEvent.setCancelled(true); - preLoginEvent.setCancelReason(DENY_LOGIN_MESSAGE_PREFIX + banReason); + String formattedMessage = formatMessageBy( + PunishmentService.KICK_LAYOUT_CONFIGURATION_KEY, + null + ); + + loginEvent.setCancelled(true); + loginEvent.setCancelReason(formattedMessage); } } } @@ -52,7 +55,11 @@ public void kickPlayer(UUID id, String kickMessage) { ProxiedPlayer player = getPlayerFrom(id); if (player == null) return; - player.disconnect(DENY_LOGIN_MESSAGE_PREFIX + kickMessage); + String formattedMessage = formatMessageBy( + PunishmentService.KICK_LAYOUT_CONFIGURATION_KEY, + null + ); + player.disconnect(formattedMessage); } @Override @@ -64,13 +71,17 @@ public void banPlayerTemporarily(UUID id, long endOfBanTimestamp, String banMess if (player == null) return; - BanEntry construct = BanEntry.builder() + BanEntry banEntry = BanEntry.builder() .withReason(banMessage) .withId(id) .withEnd(endOfBanTimestamp) .build(); - bannedPlayers.put(id, construct); - player.disconnect(DENY_LOGIN_MESSAGE_PREFIX + banMessage); + bannedPlayers.put(id, banEntry); + String formattedMessage = formatMessageBy( + PunishmentService.BAN_LAYOUT_CONFIGURATION_KEY, + banEntry + ); + player.disconnect(formattedMessage); } @Override @@ -88,7 +99,17 @@ public void banPlayer(UUID id, String banMessage) { .withAnInfiniteDuration() .build(); bannedPlayers.put(id, banEntry); - player.disconnect("[Intave] " + banMessage); + String formattedMessage = formatMessageBy( + PunishmentService.BAN_LAYOUT_CONFIGURATION_KEY, + banEntry + ); + player.disconnect(formattedMessage); + } + + private String formatMessageBy(String configurationKey, BanEntry banEntry) { + return plugin + .punishmentService() + .resolveMessageBy(configurationKey, banEntry); } private ProxiedPlayer getPlayerFrom(UUID uuid) {