Reduce the amount of tasks used for upkeep

- Ping gathering now uses a map of timestamps
  - Removes a task that waited for ping data to be reliable (one task / join)
- Cookie expiration now uses a map of timestamps
  - Removes a task that waited for cookie to expire (one task / login cookie)

Affects issues:
- Possibly fixed 
This commit is contained in:
Risto Lahtela 2022-01-06 15:43:48 +02:00
parent f26e17c437
commit a7478645bd
26 changed files with 285 additions and 119 deletions
Plan
bukkit/src
main/java/com/djrapitops/plan
gathering/timed
modules/bukkit
test/java/utilities/mocks
bungeecord/src
main/java/com/djrapitops/plan
gathering/timed
modules/bungee
test/java/utilities/mocks
common/src
main/java/com/djrapitops/plan
test/java
com/djrapitops/plan
delivery/webserver/auth
storage/database/queries
utilities/mocks
fabric/src
main/java/net/playeranalytics/plan
gathering/timed
modules/fabric
test/java/utilities/mocks
nukkit/src
main/java/com/djrapitops/plan
gathering/timed
modules/nukkit
test/java/utilities/mocks
sponge/src
main/java/com/djrapitops/plan
gathering/timed
modules/sponge
test/java/utilities/mocks
velocity/src
main/java/com/djrapitops/plan
test/java
com/djrapitops/plan/gathering/timed
utilities/mocks

View File

@ -44,6 +44,7 @@ import org.bukkit.event.player.PlayerQuitEvent;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
@ -63,13 +64,13 @@ public class BukkitPingCounter extends TaskSystem.Task implements Listener {
//https://github.com/bergerkiller/CraftSource/blob/master/net.minecraft.server/PlayerConnection.java#L178
private final Map<UUID, Long> startRecording;
private final Map<UUID, List<DateObj<Integer>>> playerHistory;
private final Listeners listeners;
private final PlanConfig config;
private final DBSystem dbSystem;
private final ServerInfo serverInfo;
private final RunnableFactory runnableFactory;
private final boolean pingMethodAvailable;
private PingMethod pingMethod;
@ -79,14 +80,13 @@ public class BukkitPingCounter extends TaskSystem.Task implements Listener {
Listeners listeners,
PlanConfig config,
DBSystem dbSystem,
ServerInfo serverInfo,
RunnableFactory runnableFactory
ServerInfo serverInfo
) {
this.listeners = listeners;
this.config = config;
this.dbSystem = dbSystem;
this.serverInfo = serverInfo;
this.runnableFactory = runnableFactory;
startRecording = new ConcurrentHashMap<>();
playerHistory = new HashMap<>();
Optional<PingMethod> pingMethod = loadPingMethod();
@ -138,6 +138,16 @@ public class BukkitPingCounter extends TaskSystem.Task implements Listener {
@Override
public void run() {
long time = System.currentTimeMillis();
Iterator<Map.Entry<UUID, Long>> starts = startRecording.entrySet().iterator();
while (starts.hasNext()) {
Map.Entry<UUID, Long> start = starts.next();
if (time >= start.getValue()) {
addPlayer(start.getKey());
starts.remove();
}
}
Iterator<Map.Entry<UUID, List<DateObj<Integer>>>> iterator = playerHistory.entrySet().iterator();
while (iterator.hasNext()) {
@ -164,11 +174,12 @@ public class BukkitPingCounter extends TaskSystem.Task implements Listener {
}
}
public void addPlayer(Player player) {
playerHistory.put(player.getUniqueId(), new ArrayList<>());
public void addPlayer(UUID uuid) {
playerHistory.put(uuid, new ArrayList<>());
}
public void removePlayer(Player player) {
startRecording.remove(player.getUniqueId());
playerHistory.remove(player.getUniqueId());
}
@ -182,15 +193,11 @@ public class BukkitPingCounter extends TaskSystem.Task implements Listener {
@EventHandler
public void onPlayerJoin(PlayerJoinEvent joinEvent) {
Player player = joinEvent.getPlayer();
Long pingDelay = config.get(TimeSettings.PING_PLAYER_LOGIN_DELAY);
if (pingDelay >= TimeUnit.HOURS.toMillis(2L)) {
Long pingDelayMs = config.get(TimeSettings.PING_PLAYER_LOGIN_DELAY);
if (pingDelayMs >= TimeUnit.HOURS.toMillis(2L)) {
return;
}
runnableFactory.create(() -> {
if (player.isOnline()) {
addPlayer(player);
}
}).runTaskLater(TimeAmount.toTicks(pingDelay, TimeUnit.MILLISECONDS));
startRecording.put(player.getUniqueId(), System.currentTimeMillis() + pingDelayMs);
}
@EventHandler

View File

@ -19,6 +19,7 @@ package com.djrapitops.plan.modules.bukkit;
import com.djrapitops.plan.TaskSystem;
import com.djrapitops.plan.delivery.web.ResourceWriteTask;
import com.djrapitops.plan.delivery.web.WebAssetVersionCheckTask;
import com.djrapitops.plan.delivery.webserver.auth.ActiveCookieExpiryCleanupTask;
import com.djrapitops.plan.delivery.webserver.cache.JSONFileStorage;
import com.djrapitops.plan.extension.ExtensionServerDataUpdater;
import com.djrapitops.plan.gathering.ShutdownDataPreservation;
@ -93,4 +94,8 @@ public interface BukkitTaskModule {
@Binds
@IntoSet
TaskSystem.Task bindWebAssetVersionCheckTask(WebAssetVersionCheckTask webAssetVersionCheckTask);
@Binds
@IntoSet
TaskSystem.Task bindActiveCookieStoreExpiryTask(ActiveCookieExpiryCleanupTask activeCookieExpiryCleanupTask);
}

View File

@ -20,6 +20,7 @@ import com.djrapitops.plan.DaggerPlanBukkitComponent;
import com.djrapitops.plan.PlanBukkitComponent;
import com.djrapitops.plan.PlanPlugin;
import com.djrapitops.plan.PlanSystem;
import com.djrapitops.plan.storage.database.SQLDB;
import org.bukkit.Server;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.scheduler.BukkitScheduler;
@ -44,6 +45,7 @@ public class BukkitMockComponent {
public BukkitMockComponent(Path tempDir) {
this.tempDir = tempDir;
SQLDB.setDownloadDriver(false);
}
public PlanPlugin getPlanMock() throws Exception {

View File

@ -44,6 +44,7 @@ import net.playeranalytics.plugin.server.Listeners;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
/**
@ -54,35 +55,43 @@ import java.util.concurrent.TimeUnit;
@Singleton
public class BungeePingCounter extends TaskSystem.Task implements Listener {
private final Map<UUID, Long> startRecording;
private final Map<UUID, List<DateObj<Integer>>> playerHistory;
private final Listeners listeners;
private final PlanConfig config;
private final DBSystem dbSystem;
private final ServerInfo serverInfo;
private final RunnableFactory runnableFactory;
@Inject
public BungeePingCounter(
Listeners listeners,
PlanConfig config,
DBSystem dbSystem,
ServerInfo serverInfo,
RunnableFactory runnableFactory
ServerInfo serverInfo
) {
this.listeners = listeners;
this.config = config;
this.dbSystem = dbSystem;
this.serverInfo = serverInfo;
this.runnableFactory = runnableFactory;
startRecording = new ConcurrentHashMap<>();
playerHistory = new HashMap<>();
}
@Override
public void run() {
long time = System.currentTimeMillis();
Iterator<Map.Entry<UUID, List<DateObj<Integer>>>> iterator = playerHistory.entrySet().iterator();
Iterator<Map.Entry<UUID, Long>> starts = startRecording.entrySet().iterator();
while (starts.hasNext()) {
Map.Entry<UUID, Long> start = starts.next();
if (time >= start.getValue()) {
addPlayer(start.getKey());
starts.remove();
}
}
Iterator<Map.Entry<UUID, List<DateObj<Integer>>>> iterator = playerHistory.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<UUID, List<DateObj<Integer>>> entry = iterator.next();
UUID uuid = entry.getKey();
@ -119,12 +128,13 @@ public class BungeePingCounter extends TaskSystem.Task implements Listener {
}
}
public void addPlayer(ProxiedPlayer player) {
playerHistory.put(player.getUniqueId(), new ArrayList<>());
public void addPlayer(UUID uuid) {
playerHistory.put(uuid, new ArrayList<>());
}
public void removePlayer(ProxiedPlayer player) {
playerHistory.remove(player.getUniqueId());
startRecording.remove(player.getUniqueId());
}
private int getPing(ProxiedPlayer player) {
@ -134,15 +144,11 @@ public class BungeePingCounter extends TaskSystem.Task implements Listener {
@EventHandler
public void onPlayerJoin(ServerConnectedEvent joinEvent) {
ProxiedPlayer player = joinEvent.getPlayer();
Long pingDelay = config.get(TimeSettings.PING_PLAYER_LOGIN_DELAY);
if (pingDelay >= TimeUnit.HOURS.toMillis(2L)) {
Long pingDelayMs = config.get(TimeSettings.PING_PLAYER_LOGIN_DELAY);
if (pingDelayMs >= TimeUnit.HOURS.toMillis(2L)) {
return;
}
runnableFactory.create(() -> {
if (player.isConnected()) {
addPlayer(player);
}
}).runTaskLater(TimeAmount.toTicks(pingDelay, TimeUnit.MILLISECONDS));
startRecording.put(player.getUniqueId(), System.currentTimeMillis() + pingDelayMs);
}
@EventHandler

View File

@ -19,6 +19,7 @@ package com.djrapitops.plan.modules.bungee;
import com.djrapitops.plan.TaskSystem;
import com.djrapitops.plan.delivery.web.ResourceWriteTask;
import com.djrapitops.plan.delivery.web.WebAssetVersionCheckTask;
import com.djrapitops.plan.delivery.webserver.auth.ActiveCookieExpiryCleanupTask;
import com.djrapitops.plan.delivery.webserver.cache.JSONFileStorage;
import com.djrapitops.plan.extension.ExtensionServerDataUpdater;
import com.djrapitops.plan.gathering.timed.BungeePingCounter;
@ -82,4 +83,8 @@ public interface BungeeTaskModule {
@Binds
@IntoSet
TaskSystem.Task bindWebAssetVersionCheckTask(WebAssetVersionCheckTask webAssetVersionCheckTask);
@Binds
@IntoSet
TaskSystem.Task bindActiveCookieStoreExpiryTask(ActiveCookieExpiryCleanupTask activeCookieExpiryCleanupTask);
}

View File

@ -20,6 +20,7 @@ import com.djrapitops.plan.DaggerPlanBungeeComponent;
import com.djrapitops.plan.PlanBungee;
import com.djrapitops.plan.PlanBungeeComponent;
import com.djrapitops.plan.PlanSystem;
import com.djrapitops.plan.storage.database.SQLDB;
import java.nio.file.Path;
@ -37,6 +38,7 @@ public class BungeeMockComponent {
public BungeeMockComponent(Path tempDir) {
this.tempDir = tempDir;
SQLDB.setDownloadDriver(false);
}
public PlanBungee getPlanMock() throws Exception {

View File

@ -0,0 +1,73 @@
/*
* This file is part of Player Analytics (Plan).
*
* Plan is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License v3 as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Plan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
*/
package com.djrapitops.plan.delivery.webserver.auth;
import com.djrapitops.plan.TaskSystem;
import dagger.Lazy;
import net.playeranalytics.plugin.scheduling.RunnableFactory;
import net.playeranalytics.plugin.scheduling.TimeAmount;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
@Singleton
public class ActiveCookieExpiryCleanupTask extends TaskSystem.Task {
private final Lazy<ActiveCookieStore> activeCookieStore;
private final Map<String, Long> expiryDates;
@Inject
public ActiveCookieExpiryCleanupTask(Lazy<ActiveCookieStore> activeCookieStore) {
this.activeCookieStore = activeCookieStore;
this.expiryDates = new ConcurrentHashMap<>();
}
@Override
public void register(RunnableFactory runnableFactory) {
runnableFactory.create(this)
.runTaskTimerAsynchronously(
TimeAmount.toTicks(5, TimeUnit.SECONDS),
TimeAmount.toTicks(1, TimeUnit.SECONDS));
}
@Override
public void run() {
long time = System.currentTimeMillis();
Set<String> removed = new HashSet<>();
for (Map.Entry<String, Long> entry : expiryDates.entrySet()) {
Long expiryTime = entry.getValue();
if (expiryTime >= time) {
String cookie = entry.getKey();
activeCookieStore.get().removeCookie(cookie);
}
}
for (String removedCookie : removed) {
expiryDates.remove(removedCookie);
}
}
public void addExpiry(String cookie, Long time) {
expiryDates.put(cookie, time);
}
}

View File

@ -24,14 +24,13 @@ import com.djrapitops.plan.settings.config.paths.WebserverSettings;
import com.djrapitops.plan.storage.database.DBSystem;
import com.djrapitops.plan.storage.database.queries.objects.WebUserQueries;
import com.djrapitops.plan.storage.database.transactions.events.CookieChangeTransaction;
import net.playeranalytics.plugin.scheduling.RunnableFactory;
import net.playeranalytics.plugin.scheduling.Task;
import net.playeranalytics.plugin.scheduling.TimeAmount;
import org.apache.commons.codec.digest.DigestUtils;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.*;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
@ -42,28 +41,25 @@ public class ActiveCookieStore implements SubSystem {
public static long cookieExpiresAfter = TimeUnit.HOURS.toMillis(2L);
private static ActiveCookieStore activeCookieStore;
private final ActiveCookieExpiryCleanupTask activeCookieExpiryCleanupTask;
private final PlanConfig config;
private final DBSystem dbSystem;
private final RunnableFactory runnableFactory;
private final Processing processing;
private final Collection<Task> expiryTasks;
@Inject
public ActiveCookieStore(
ActiveCookieExpiryCleanupTask activeCookieExpiryCleanupTask,
PlanConfig config,
DBSystem dbSystem,
RunnableFactory runnableFactory,
Processing processing
) {
this.activeCookieExpiryCleanupTask = activeCookieExpiryCleanupTask;
ActiveCookieStore.activeCookieStore = this;
this.config = config;
this.dbSystem = dbSystem;
this.processing = processing;
this.runnableFactory = runnableFactory;
expiryTasks = new ArrayList<>();
}
private static void removeCookieStatic(String cookie) {
@ -88,22 +84,13 @@ public class ActiveCookieStore implements SubSystem {
USERS_BY_COOKIE.putAll(dbSystem.getDatabase().query(WebUserQueries.fetchActiveCookies()));
for (Map.Entry<String, Long> entry : dbSystem.getDatabase().query(WebUserQueries.getCookieExpiryTimes()).entrySet()) {
long timeToExpiry = Math.max(entry.getValue() - System.currentTimeMillis(), 0L);
expiryTasks.add(runnableFactory.create(() -> removeCookie(entry.getKey()))
.runTaskLaterAsynchronously(TimeAmount.toTicks(timeToExpiry, TimeUnit.MILLISECONDS)));
activeCookieExpiryCleanupTask.addExpiry(entry.getKey(), System.currentTimeMillis() + timeToExpiry);
}
}
@Override
public void disable() {
USERS_BY_COOKIE.clear();
expiryTasks.forEach(task -> {
try {
task.cancel();
} catch (Exception e) {
// Ignore, task has already been cancelled
}
});
expiryTasks.clear();
}
public Optional<User> checkCookie(String cookie) {
@ -114,8 +101,7 @@ public class ActiveCookieStore implements SubSystem {
String cookie = DigestUtils.sha256Hex(user.getUsername() + UUID.randomUUID() + System.currentTimeMillis());
USERS_BY_COOKIE.put(cookie, user);
saveNewCookie(user, cookie, System.currentTimeMillis());
expiryTasks.add(runnableFactory.create(() -> removeCookie(cookie))
.runTaskLaterAsynchronously(TimeAmount.toTicks(cookieExpiresAfter, TimeUnit.MILLISECONDS)));
activeCookieExpiryCleanupTask.addExpiry(cookie, System.currentTimeMillis() + cookieExpiresAfter);
return cookie;
}

View File

@ -16,7 +16,7 @@
*/
package com.djrapitops.plan.settings;
import net.playeranalytics.plugin.scheduling.RunnableFactory;
import com.djrapitops.plan.processing.Processing;
import javax.inject.Inject;
import javax.inject.Singleton;
@ -24,16 +24,16 @@ import javax.inject.Singleton;
@Singleton
public class SchedulerSvc implements SchedulerService {
private final RunnableFactory runnableFactory;
private final Processing processing;
@Inject
public SchedulerSvc(RunnableFactory runnableFactory) {
this.runnableFactory = runnableFactory;
public SchedulerSvc(Processing processing) {
this.processing = processing;
}
@Override
public void runAsync(Runnable runnable) {
runnableFactory.create(runnable).runTaskAsynchronously();
processing.submitNonCritical(runnable);
}
public void register() {

View File

@ -46,6 +46,7 @@ import net.playeranalytics.plugin.scheduling.TimeAmount;
import net.playeranalytics.plugin.server.PluginLogger;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.*;
@ -60,6 +61,8 @@ import java.util.function.Supplier;
*/
public abstract class SQLDB extends AbstractDatabase {
private static boolean downloadDriver = true;
private static final List<Repository> DRIVER_REPOSITORIES = Arrays.asList(
new StandardRepository("https://papermc.io/repo/repository/maven-public/"),
new StandardRepository("https://repo1.maven.org/maven2/")
@ -74,7 +77,7 @@ public abstract class SQLDB extends AbstractDatabase {
protected final PluginLogger logger;
protected final ErrorLogger errorLogger;
protected IsolatedClassLoader driverClassLoader;
protected ClassLoader driverClassLoader;
private Supplier<ExecutorService> transactionExecutorServiceProvider;
private ExecutorService transactionExecutor;
@ -110,16 +113,24 @@ public abstract class SQLDB extends AbstractDatabase {
};
}
public static void setDownloadDriver(boolean downloadDriver) {
SQLDB.downloadDriver = downloadDriver;
}
protected abstract List<String> getDependencyResource();
public void downloadDriver() {
DependencyManager dependencyManager = new DependencyManager(files.getDataDirectory().resolve("libraries"));
dependencyManager.loadFromResource(getDependencyResource());
dependencyManager.download(null, DRIVER_REPOSITORIES);
if (downloadDriver) {
DependencyManager dependencyManager = new DependencyManager(files.getDataDirectory().resolve("libraries"));
dependencyManager.loadFromResource(getDependencyResource());
dependencyManager.download(null, DRIVER_REPOSITORIES);
IsolatedClassLoader classLoader = new IsolatedClassLoader();
dependencyManager.load(null, classLoader);
this.driverClassLoader = classLoader;
IsolatedClassLoader classLoader = new IsolatedClassLoader();
dependencyManager.load(null, classLoader);
this.driverClassLoader = classLoader;
} else {
this.driverClassLoader = getClass().getClassLoader();
}
}
@Override
@ -262,9 +273,21 @@ public abstract class SQLDB extends AbstractDatabase {
public void close() {
if (getState() == State.OPEN) setState(State.CLOSING);
closeTransactionExecutor(transactionExecutor);
unloadDriverClassloader();
setState(State.CLOSED);
}
private void unloadDriverClassloader() {
try {
if (driverClassLoader != null && driverClassLoader instanceof IsolatedClassLoader) {
((IsolatedClassLoader) driverClassLoader).close();
}
driverClassLoader = null;
} catch (IOException e) {
errorLogger.error(e, ErrorContext.builder().build());
}
}
public abstract Connection getConnection() throws SQLException;
public abstract void returnToPool(Connection connection);

View File

@ -46,7 +46,7 @@ class ActiveCookieStoreTest {
when(dbSystem.getDatabase()).thenReturn(db);
underTest = new ActiveCookieStore(
Mockito.mock(PlanConfig.class),
activeCookieExpiryCleanupTask, Mockito.mock(PlanConfig.class),
dbSystem,
new TestRunnableFactory(),
Mockito.mock(Processing.class)

View File

@ -78,7 +78,7 @@ public interface WebUserQueriesTest extends DatabaseTestPreparer {
userIsRegistered();
User user = db().query(WebUserQueries.fetchUser(WEB_USERNAME)).orElseThrow(AssertionError::new);
ActiveCookieStore cookieStore = new ActiveCookieStore(Mockito.mock(PlanConfig.class), dbSystem(), new TestRunnableFactory(), Mockito.mock(Processing.class));
ActiveCookieStore cookieStore = new ActiveCookieStore(activeCookieExpiryCleanupTask, Mockito.mock(PlanConfig.class), dbSystem(), new TestRunnableFactory(), Mockito.mock(Processing.class));
String cookie = cookieStore.generateNewCookie(user);
@ -92,7 +92,7 @@ public interface WebUserQueriesTest extends DatabaseTestPreparer {
userIsRegistered();
User user = db().query(WebUserQueries.fetchUser(WEB_USERNAME)).orElseThrow(AssertionError::new);
ActiveCookieStore cookieStore = new ActiveCookieStore(Mockito.mock(PlanConfig.class), dbSystem(), new TestRunnableFactory(), Mockito.mock(Processing.class));
ActiveCookieStore cookieStore = new ActiveCookieStore(activeCookieExpiryCleanupTask, Mockito.mock(PlanConfig.class), dbSystem(), new TestRunnableFactory(), Mockito.mock(Processing.class));
String cookie = cookieStore.generateNewCookie(user);
@ -106,7 +106,7 @@ public interface WebUserQueriesTest extends DatabaseTestPreparer {
userIsRegistered();
User user = db().query(WebUserQueries.fetchUser(WEB_USERNAME)).orElseThrow(AssertionError::new);
ActiveCookieStore cookieStore = new ActiveCookieStore(Mockito.mock(PlanConfig.class), dbSystem(), new TestRunnableFactory(), Mockito.mock(Processing.class));
ActiveCookieStore cookieStore = new ActiveCookieStore(activeCookieExpiryCleanupTask, Mockito.mock(PlanConfig.class), dbSystem(), new TestRunnableFactory(), Mockito.mock(Processing.class));
String cookie = cookieStore.generateNewCookie(user);

View File

@ -18,6 +18,7 @@ package utilities.mocks;
import com.djrapitops.plan.PlanPlugin;
import com.djrapitops.plan.PlanSystem;
import com.djrapitops.plan.storage.database.SQLDB;
import com.djrapitops.plan.utilities.logging.PluginErrorLogger;
import net.playeranalytics.plugin.PlatformAbstractionLayer;
import utilities.dagger.DaggerPlanPluginComponent;
@ -40,6 +41,7 @@ public class PluginMockComponent {
public PluginMockComponent(Path tempDir) {
this.tempDir = tempDir;
SQLDB.setDownloadDriver(false);
}
public PlanPlugin getPlanMock() throws Exception {

View File

@ -41,6 +41,7 @@ import net.playeranalytics.plugin.server.Listeners;
import javax.inject.Inject;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
/**
@ -51,13 +52,13 @@ import java.util.concurrent.TimeUnit;
*/
public class FabricPingCounter extends TaskSystem.Task implements FabricListener {
private final Map<UUID, Long> startRecording;
private final Map<UUID, List<DateObj<Integer>>> playerHistory;
private final Listeners listeners;
private final PlanConfig config;
private final DBSystem dbSystem;
private final ServerInfo serverInfo;
private final RunnableFactory runnableFactory;
private final MinecraftDedicatedServer server;
private boolean isEnabled = false;
@ -68,15 +69,14 @@ public class FabricPingCounter extends TaskSystem.Task implements FabricListener
PlanConfig config,
DBSystem dbSystem,
ServerInfo serverInfo,
RunnableFactory runnableFactory,
MinecraftDedicatedServer server
) {
this.listeners = listeners;
this.config = config;
this.dbSystem = dbSystem;
this.serverInfo = serverInfo;
this.runnableFactory = runnableFactory;
this.server = server;
startRecording = new ConcurrentHashMap<>();
playerHistory = new HashMap<>();
ServerPlayConnectionEvents.JOIN.register((handler, sender, minecraftServer) -> onPlayerJoin(handler.player));
ServerPlayConnectionEvents.DISCONNECT.register((handler, minecraftServer) -> onPlayerQuit(handler.player));
@ -88,6 +88,16 @@ public class FabricPingCounter extends TaskSystem.Task implements FabricListener
return;
}
long time = System.currentTimeMillis();
Iterator<Map.Entry<UUID, Long>> starts = startRecording.entrySet().iterator();
while (starts.hasNext()) {
Map.Entry<UUID, Long> start = starts.next();
if (time >= start.getValue()) {
addPlayer(start.getKey());
starts.remove();
}
}
Iterator<Map.Entry<UUID, List<DateObj<Integer>>>> iterator = playerHistory.entrySet().iterator();
while (iterator.hasNext()) {
@ -126,12 +136,13 @@ public class FabricPingCounter extends TaskSystem.Task implements FabricListener
this.enable();
}
public void addPlayer(ServerPlayerEntity player) {
playerHistory.put(player.getUuid(), new ArrayList<>());
public void addPlayer(UUID uuid) {
playerHistory.put(uuid, new ArrayList<>());
}
public void removePlayer(ServerPlayerEntity player) {
playerHistory.remove(player.getUuid());
startRecording.remove(player.getUuid());
}
private int getPing(ServerPlayerEntity player) {
@ -143,15 +154,11 @@ public class FabricPingCounter extends TaskSystem.Task implements FabricListener
return;
}
Long pingDelay = config.get(TimeSettings.PING_PLAYER_LOGIN_DELAY);
if (pingDelay >= TimeUnit.HOURS.toMillis(2L)) {
Long pingDelayMs = config.get(TimeSettings.PING_PLAYER_LOGIN_DELAY);
if (pingDelayMs >= TimeUnit.HOURS.toMillis(2L)) {
return;
}
runnableFactory.create(() -> {
if (server.getPlayerManager().getPlayerList().contains(player)) {
addPlayer(player);
}
}).runTaskLater(TimeAmount.toTicks(pingDelay, TimeUnit.MILLISECONDS));
startRecording.put(player.getUuid(), System.currentTimeMillis() + pingDelayMs);
}
public void onPlayerQuit(ServerPlayerEntity player) {

View File

@ -18,6 +18,7 @@ package net.playeranalytics.plan.modules.fabric;
import com.djrapitops.plan.TaskSystem;
import com.djrapitops.plan.delivery.web.ResourceWriteTask;
import com.djrapitops.plan.delivery.webserver.auth.ActiveCookieExpiryCleanupTask;
import com.djrapitops.plan.delivery.webserver.cache.JSONFileStorage;
import com.djrapitops.plan.extension.ExtensionServerDataUpdater;
import com.djrapitops.plan.gathering.ShutdownDataPreservation;
@ -88,4 +89,8 @@ public interface FabricTaskModule {
@Binds
@IntoSet
TaskSystem.Task bindResourceWriteTask(ResourceWriteTask resourceWriteTask);
@Binds
@IntoSet
TaskSystem.Task bindActiveCookieStoreExpiryTask(ActiveCookieExpiryCleanupTask activeCookieExpiryCleanupTask);
}

View File

@ -18,6 +18,7 @@ package utilities.mocks;
import com.djrapitops.plan.PlanPlugin;
import com.djrapitops.plan.PlanSystem;
import com.djrapitops.plan.storage.database.SQLDB;
import net.minecraft.server.dedicated.MinecraftDedicatedServer;
import net.playeranalytics.plan.DaggerPlanFabricComponent;
import net.playeranalytics.plan.PlanFabricComponent;
@ -43,6 +44,7 @@ public class FabricMockComponent {
public FabricMockComponent(Path tempDir) {
this.tempDir = tempDir;
SQLDB.setDownloadDriver(false);
}
public PlanPlugin getPlanMock() {

View File

@ -44,6 +44,7 @@ import net.playeranalytics.plugin.server.Listeners;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
/**
@ -57,33 +58,42 @@ import java.util.concurrent.TimeUnit;
@Singleton
public class NukkitPingCounter extends TaskSystem.Task implements Listener {
private final Map<UUID, Long> startRecording;
private final Map<UUID, List<DateObj<Integer>>> playerHistory;
private final Listeners listeners;
private final PlanConfig config;
private final DBSystem dbSystem;
private final ServerInfo serverInfo;
private final RunnableFactory runnableFactory;
@Inject
public NukkitPingCounter(
Listeners listeners,
PlanConfig config,
DBSystem dbSystem,
ServerInfo serverInfo,
RunnableFactory runnableFactory
ServerInfo serverInfo
) {
this.listeners = listeners;
this.config = config;
this.dbSystem = dbSystem;
this.serverInfo = serverInfo;
this.runnableFactory = runnableFactory;
startRecording = new ConcurrentHashMap<>();
playerHistory = new HashMap<>();
}
@Override
public void run() {
long time = System.currentTimeMillis();
Iterator<Map.Entry<UUID, Long>> starts = startRecording.entrySet().iterator();
while (starts.hasNext()) {
Map.Entry<UUID, Long> start = starts.next();
if (time >= start.getValue()) {
addPlayer(start.getKey());
starts.remove();
}
}
Iterator<Map.Entry<UUID, List<DateObj<Integer>>>> iterator = playerHistory.entrySet().iterator();
while (iterator.hasNext()) {
@ -121,26 +131,23 @@ public class NukkitPingCounter extends TaskSystem.Task implements Listener {
}
}
public void addPlayer(Player player) {
playerHistory.put(player.getUniqueId(), new ArrayList<>());
public void addPlayer(UUID uuid) {
playerHistory.put(uuid, new ArrayList<>());
}
public void removePlayer(Player player) {
playerHistory.remove(player.getUniqueId());
startRecording.remove(player.getUniqueId());
}
@EventHandler
public void onPlayerJoin(PlayerJoinEvent joinEvent) {
Player player = joinEvent.getPlayer();
Long pingDelay = config.get(TimeSettings.PING_PLAYER_LOGIN_DELAY);
if (pingDelay >= TimeUnit.HOURS.toMillis(2L)) {
Long pingDelayMs = config.get(TimeSettings.PING_PLAYER_LOGIN_DELAY);
if (pingDelayMs >= TimeUnit.HOURS.toMillis(2L)) {
return;
}
runnableFactory.create(() -> {
if (player.isOnline()) {
addPlayer(player);
}
}).runTaskLater(TimeAmount.toTicks(pingDelay, TimeUnit.MILLISECONDS));
startRecording.put(player.getUniqueId(), System.currentTimeMillis() + pingDelayMs);
}
@EventHandler

View File

@ -20,6 +20,7 @@ import cn.nukkit.level.Level;
import com.djrapitops.plan.TaskSystem;
import com.djrapitops.plan.delivery.web.ResourceWriteTask;
import com.djrapitops.plan.delivery.web.WebAssetVersionCheckTask;
import com.djrapitops.plan.delivery.webserver.auth.ActiveCookieExpiryCleanupTask;
import com.djrapitops.plan.delivery.webserver.cache.JSONFileStorage;
import com.djrapitops.plan.extension.ExtensionServerDataUpdater;
import com.djrapitops.plan.gathering.ShutdownDataPreservation;
@ -93,4 +94,8 @@ public interface NukkitTaskModule {
@Binds
@IntoSet
TaskSystem.Task bindWebAssetVersionCheckTask(WebAssetVersionCheckTask webAssetVersionCheckTask);
@Binds
@IntoSet
TaskSystem.Task bindActiveCookieStoreExpiryTask(ActiveCookieExpiryCleanupTask activeCookieExpiryCleanupTask);
}

View File

@ -20,6 +20,7 @@ import com.djrapitops.plan.DaggerPlanNukkitComponent;
import com.djrapitops.plan.PlanNukkit;
import com.djrapitops.plan.PlanNukkitComponent;
import com.djrapitops.plan.PlanSystem;
import com.djrapitops.plan.storage.database.SQLDB;
import java.nio.file.Path;
@ -37,6 +38,7 @@ public class NukkitMockComponent {
public NukkitMockComponent(Path tempDir) {
this.tempDir = tempDir;
SQLDB.setDownloadDriver(false);
}
public PlanNukkit getPlanMock() throws Exception {

View File

@ -41,6 +41,7 @@ import org.spongepowered.api.event.network.ClientConnectionEvent;
import javax.inject.Inject;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
/**
@ -50,33 +51,42 @@ import java.util.concurrent.TimeUnit;
*/
public class SpongePingCounter extends TaskSystem.Task {
private final Map<UUID, Long> startRecording;
private final Map<UUID, List<DateObj<Integer>>> playerHistory;
private final Listeners listeners;
private final PlanConfig config;
private final DBSystem dbSystem;
private final ServerInfo serverInfo;
private final RunnableFactory runnableFactory;
@Inject
public SpongePingCounter(
Listeners listeners,
PlanConfig config,
DBSystem dbSystem,
ServerInfo serverInfo,
RunnableFactory runnableFactory
ServerInfo serverInfo
) {
this.listeners = listeners;
this.config = config;
this.dbSystem = dbSystem;
this.serverInfo = serverInfo;
this.runnableFactory = runnableFactory;
playerHistory = new HashMap<>();
startRecording = new ConcurrentHashMap<>();
}
@Override
public void run() {
long time = System.currentTimeMillis();
Iterator<Map.Entry<UUID, Long>> starts = startRecording.entrySet().iterator();
while (starts.hasNext()) {
Map.Entry<UUID, Long> start = starts.next();
if (time >= start.getValue()) {
addPlayer(start.getKey());
starts.remove();
}
}
Iterator<Map.Entry<UUID, List<DateObj<Integer>>>> iterator = playerHistory.entrySet().iterator();
while (iterator.hasNext()) {
@ -114,12 +124,13 @@ public class SpongePingCounter extends TaskSystem.Task {
}
}
public void addPlayer(Player player) {
playerHistory.put(player.getUniqueId(), new ArrayList<>());
public void addPlayer(UUID uuid) {
playerHistory.put(uuid, new ArrayList<>());
}
public void removePlayer(Player player) {
playerHistory.remove(player.getUniqueId());
startRecording.remove(player.getUniqueId());
}
private int getPing(Player player) {
@ -129,15 +140,11 @@ public class SpongePingCounter extends TaskSystem.Task {
@Listener
public void onPlayerJoin(ClientConnectionEvent.Join joinEvent) {
Player player = joinEvent.getTargetEntity();
Long pingDelay = config.get(TimeSettings.PING_PLAYER_LOGIN_DELAY);
if (pingDelay >= TimeUnit.HOURS.toMillis(2L)) {
Long pingDelayMs = config.get(TimeSettings.PING_PLAYER_LOGIN_DELAY);
if (pingDelayMs >= TimeUnit.HOURS.toMillis(2L)) {
return;
}
runnableFactory.create(() -> {
if (player.isOnline()) {
addPlayer(player);
}
}).runTaskLater(TimeAmount.toTicks(pingDelay, TimeUnit.MILLISECONDS));
startRecording.put(player.getUniqueId(), System.currentTimeMillis() + pingDelayMs);
}
@Listener

View File

@ -19,6 +19,7 @@ package com.djrapitops.plan.modules.sponge;
import com.djrapitops.plan.TaskSystem;
import com.djrapitops.plan.delivery.web.ResourceWriteTask;
import com.djrapitops.plan.delivery.web.WebAssetVersionCheckTask;
import com.djrapitops.plan.delivery.webserver.auth.ActiveCookieExpiryCleanupTask;
import com.djrapitops.plan.delivery.webserver.cache.JSONFileStorage;
import com.djrapitops.plan.extension.ExtensionServerDataUpdater;
import com.djrapitops.plan.gathering.ShutdownDataPreservation;
@ -93,4 +94,8 @@ public interface SpongeTaskModule {
@Binds
@IntoSet
TaskSystem.Task bindWebAssetVersionCheckTask(WebAssetVersionCheckTask webAssetVersionCheckTask);
@Binds
@IntoSet
TaskSystem.Task bindActiveCookieStoreExpiryTask(ActiveCookieExpiryCleanupTask activeCookieExpiryCleanupTask);
}

View File

@ -20,6 +20,7 @@ import com.djrapitops.plan.DaggerPlanSpongeComponent;
import com.djrapitops.plan.PlanPlugin;
import com.djrapitops.plan.PlanSpongeComponent;
import com.djrapitops.plan.PlanSystem;
import com.djrapitops.plan.storage.database.SQLDB;
import org.mockito.Mockito;
import org.spongepowered.api.Game;
import org.spongepowered.api.MinecraftVersion;
@ -50,6 +51,7 @@ public class SpongeMockComponent {
public SpongeMockComponent(Path tempDir) {
this.tempDir = tempDir;
SQLDB.setDownloadDriver(false);
}
public PlanPlugin getPlanMock() throws Exception {

View File

@ -43,6 +43,7 @@ import net.playeranalytics.plugin.server.Listeners;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
/**
@ -55,6 +56,7 @@ import java.util.concurrent.TimeUnit;
@Singleton
public class VelocityPingCounter extends TaskSystem.Task {
private final Map<UUID, Long> startRecording;
final Map<UUID, List<DateObj<Integer>>> playerHistory;
private final Listeners listeners;
@ -62,7 +64,6 @@ public class VelocityPingCounter extends TaskSystem.Task {
private final PlanConfig config;
private final DBSystem dbSystem;
private final ServerInfo serverInfo;
private final RunnableFactory runnableFactory;
@Inject
public VelocityPingCounter(
@ -70,21 +71,30 @@ public class VelocityPingCounter extends TaskSystem.Task {
PlanVelocity plugin,
PlanConfig config,
DBSystem dbSystem,
ServerInfo serverInfo,
RunnableFactory runnableFactory
ServerInfo serverInfo
) {
this.listeners = listeners;
this.plugin = plugin;
this.config = config;
this.dbSystem = dbSystem;
this.serverInfo = serverInfo;
this.runnableFactory = runnableFactory;
startRecording = new ConcurrentHashMap<>();
playerHistory = new HashMap<>();
}
@Override
public void run() {
long time = System.currentTimeMillis();
Iterator<Map.Entry<UUID, Long>> starts = startRecording.entrySet().iterator();
while (starts.hasNext()) {
Map.Entry<UUID, Long> start = starts.next();
if (time >= start.getValue()) {
addPlayer(start.getKey());
starts.remove();
}
}
Iterator<Map.Entry<UUID, List<DateObj<Integer>>>> iterator = playerHistory.entrySet().iterator();
while (iterator.hasNext()) {
@ -122,8 +132,8 @@ public class VelocityPingCounter extends TaskSystem.Task {
}
}
void addPlayer(Player player) {
playerHistory.put(player.getUniqueId(), new ArrayList<>());
void addPlayer(UUID playerUuid) {
playerHistory.put(playerUuid, new ArrayList<>());
}
public void removePlayer(Player player) {
@ -137,15 +147,11 @@ public class VelocityPingCounter extends TaskSystem.Task {
@Subscribe
public void onPlayerJoin(ServerConnectedEvent joinEvent) {
Player player = joinEvent.getPlayer();
Long pingDelay = config.get(TimeSettings.PING_PLAYER_LOGIN_DELAY);
if (pingDelay >= TimeUnit.HOURS.toMillis(2L)) {
Long pingDelayMs = config.get(TimeSettings.PING_PLAYER_LOGIN_DELAY);
if (pingDelayMs >= TimeUnit.HOURS.toMillis(2L)) {
return;
}
runnableFactory.create(() -> {
if (player.isActive()) {
addPlayer(player);
}
}).runTaskLater(TimeAmount.toTicks(pingDelay, TimeUnit.MILLISECONDS));
startRecording.put(player.getUniqueId(), System.currentTimeMillis() + pingDelayMs);
}
@Subscribe

View File

@ -19,6 +19,7 @@ package com.djrapitops.plan.modules.velocity;
import com.djrapitops.plan.TaskSystem;
import com.djrapitops.plan.delivery.web.ResourceWriteTask;
import com.djrapitops.plan.delivery.web.WebAssetVersionCheckTask;
import com.djrapitops.plan.delivery.webserver.auth.ActiveCookieExpiryCleanupTask;
import com.djrapitops.plan.delivery.webserver.cache.JSONFileStorage;
import com.djrapitops.plan.extension.ExtensionServerDataUpdater;
import com.djrapitops.plan.gathering.timed.ProxyTPSCounter;
@ -82,4 +83,8 @@ public interface VelocityTaskModule {
@Binds
@IntoSet
TaskSystem.Task bindWebAssetVersionCheckTask(WebAssetVersionCheckTask webAssetVersionCheckTask);
@Binds
@IntoSet
TaskSystem.Task bindActiveCookieStoreExpiryTask(ActiveCookieExpiryCleanupTask activeCookieExpiryCleanupTask);
}

View File

@ -58,10 +58,10 @@ class VelocityPingCounterTest {
@Test
void offlinePlayerIsRemovedFromPlayerHistory() {
VelocityPingCounter counter = new VelocityPingCounter(Mockito.mock(Listeners.class), plugin, null, null, null, null);
VelocityPingCounter counter = new VelocityPingCounter(Mockito.mock(Listeners.class), plugin, null, null, null);
assertTrue(counter.playerHistory.isEmpty());
counter.addPlayer(player);
counter.addPlayer(player.getUniqueId());
assertFalse(counter.playerHistory.isEmpty());
counter.run();

View File

@ -20,6 +20,7 @@ import com.djrapitops.plan.DaggerPlanVelocityComponent;
import com.djrapitops.plan.PlanSystem;
import com.djrapitops.plan.PlanVelocity;
import com.djrapitops.plan.PlanVelocityComponent;
import com.djrapitops.plan.storage.database.SQLDB;
import java.nio.file.Path;
@ -37,6 +38,7 @@ public class VelocityMockComponent {
public VelocityMockComponent(Path tempDir) {
this.tempDir = tempDir;
SQLDB.setDownloadDriver(false);
}
public PlanVelocity getPlanMock() throws Exception {