mirror of
https://github.com/plan-player-analytics/Plan.git
synced 2024-11-01 00:10:12 +01:00
[Merge] 4.7.0 (#941)
This commit is contained in:
commit
45b33e49e0
@ -12,9 +12,10 @@ allprojects {
|
||||
wrapper.gradleVersion = "5.0"
|
||||
|
||||
group "com.djrapitops"
|
||||
version "4.6.2-SNAPSHOT"
|
||||
version "4.7.0"
|
||||
|
||||
test {
|
||||
// useJUnitPlatform()
|
||||
testLogging {
|
||||
events "passed", "failed"
|
||||
exceptionFormat "full"
|
||||
@ -30,7 +31,7 @@ allprojects {
|
||||
subprojects {
|
||||
// Build plugins
|
||||
apply plugin: "java"
|
||||
apply plugin: "maven"
|
||||
apply plugin: "maven-publish"
|
||||
apply plugin: "net.ltgt.apt" // Annotation processing plugin
|
||||
apply plugin: "net.ltgt.apt-idea" // Annotation processing IntelliJ IDEA configuration plugin
|
||||
apply plugin: "com.github.johnrengelman.shadow"
|
||||
@ -46,7 +47,7 @@ subprojects {
|
||||
ext.daggerCompilerVersion = "2.21"
|
||||
|
||||
ext.abstractPluginFrameworkVersion = "3.4.1"
|
||||
ext.planPluginBridgeVersion = "4.6.2"
|
||||
ext.planPluginBridgeVersion = "4.7.0"
|
||||
|
||||
ext.bukkitVersion = "1.12.2-R0.1-SNAPSHOT"
|
||||
ext.spigotVersion = "1.12.2-R0.1-SNAPSHOT"
|
||||
@ -59,10 +60,10 @@ subprojects {
|
||||
ext.httpClientVersion = "4.5.7"
|
||||
ext.commonsTextVersion = "1.6"
|
||||
ext.htmlCompressorVersion = "1.5.2"
|
||||
ext.caffeineVersion = "2.6.2"
|
||||
ext.caffeineVersion = "2.7.0"
|
||||
ext.h2Version = "1.4.196"
|
||||
ext.hikariVersion = "3.3.0"
|
||||
ext.slf4jVersion = "1.7.25"
|
||||
ext.hikariVersion = "3.3.1"
|
||||
ext.slf4jVersion = "1.7.26"
|
||||
ext.geoIpVersion = "2.12.0"
|
||||
ext.guavaVersion = "26.0-jre"
|
||||
ext.bstatsVersion = "1.2"
|
||||
@ -102,13 +103,12 @@ subprojects {
|
||||
testAnnotationProcessor "com.google.dagger:dagger-compiler:$daggerCompilerVersion"
|
||||
|
||||
// Test Tooling Dependencies
|
||||
testCompile "org.junit.jupiter:junit-jupiter-engine:5.3.2" // JUnit 5
|
||||
testCompile "org.junit.platform:junit-platform-runner:1.3.2" // JUnit 4 runner for JUnit 5 tests
|
||||
testCompile "org.junit.vintage:junit-vintage-engine:5.3.2" // JUnit 4 compatibility for JUnit 5
|
||||
testCompile "org.junit.jupiter:junit-jupiter-params:5.3.2" // JUnit 5, parameterized tests
|
||||
testCompile "org.junit-pioneer:junit-pioneer:0.3.0" // TempDirectory TODO REMOVE W/ JUNIT 5.4
|
||||
testCompile "org.mockito:mockito-core:2.24.0" // Mockito Core
|
||||
testCompile "org.mockito:mockito-junit-jupiter:2.24.0" // Mockito JUnit 5 Extension
|
||||
testCompile "org.junit.jupiter:junit-jupiter-engine:5.4.0" // JUnit 5
|
||||
testCompile "org.junit.platform:junit-platform-runner:1.4.0" // JUnit 4 runner for JUnit 5 tests
|
||||
testCompile "org.junit.vintage:junit-vintage-engine:5.4.0" // JUnit 4 compatibility for JUnit 5
|
||||
testCompile "org.junit.jupiter:junit-jupiter-params:5.4.0" // JUnit 5, parameterized tests
|
||||
testCompile "org.mockito:mockito-core:2.24.5" // Mockito Core
|
||||
testCompile "org.mockito:mockito-junit-jupiter:2.24.5" // Mockito JUnit 5 Extension
|
||||
testCompile "org.seleniumhq.selenium:selenium-java:3.141.59" // Selenium (Browser tests)
|
||||
testCompile "com.jayway.awaitility:awaitility:1.7.0" // Awaitility (Concurrent wait conditions)
|
||||
|
||||
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.locale.Locale;
|
||||
import com.djrapitops.plan.utilities.java.Reflection;
|
||||
import com.djrapitops.plugin.logging.console.PluginLogger;
|
||||
import com.djrapitops.plugin.logging.error.ErrorHandler;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
/**
|
||||
* ServerShutdownSave implementation for Bukkit based servers.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Singleton
|
||||
public class BukkitServerShutdownSave extends ServerShutdownSave {
|
||||
|
||||
@Inject
|
||||
public BukkitServerShutdownSave(
|
||||
Locale locale,
|
||||
DBSystem dbSystem,
|
||||
PluginLogger logger,
|
||||
ErrorHandler errorHandler
|
||||
) {
|
||||
super(locale, dbSystem, logger, errorHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean checkServerShuttingDownStatus() {
|
||||
try {
|
||||
return performCheck();
|
||||
} catch (Exception | NoClassDefFoundError | NoSuchFieldError e) {
|
||||
logger.debug("Server shutdown check failed, using JVM ShutdownHook instead. Error: " + e.toString());
|
||||
return false; // ShutdownHook handles save in case this fails upon plugin disable.
|
||||
}
|
||||
}
|
||||
|
||||
private boolean performCheck() {
|
||||
// Special thanks to Fuzzlemann for figuring out the methods required for this check.
|
||||
// https://github.com/Rsl1122/Plan-PlayerAnalytics/issues/769#issuecomment-433898242
|
||||
Class<?> minecraftServerClass = Reflection.getMinecraftClass("MinecraftServer");
|
||||
Object minecraftServer = Reflection.getField(minecraftServerClass, "SERVER", minecraftServerClass).get(null);
|
||||
|
||||
return Reflection.getField(minecraftServerClass, "isStopped", boolean.class).get(minecraftServer);
|
||||
}
|
||||
}
|
@ -40,6 +40,7 @@ public class Plan extends BukkitPlugin implements PlanPlugin {
|
||||
|
||||
private PlanSystem system;
|
||||
private Locale locale;
|
||||
private ServerShutdownSave serverShutdownSave;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
@ -47,6 +48,7 @@ public class Plan extends BukkitPlugin implements PlanPlugin {
|
||||
try {
|
||||
timings.start("Enable");
|
||||
system = component.system();
|
||||
serverShutdownSave = component.serverShutdownSave();
|
||||
locale = system.getLocaleSystem().getLocale();
|
||||
system.enable();
|
||||
|
||||
@ -88,6 +90,9 @@ public class Plan extends BukkitPlugin implements PlanPlugin {
|
||||
*/
|
||||
@Override
|
||||
public void onDisable() {
|
||||
if (serverShutdownSave != null) {
|
||||
serverShutdownSave.performSave();
|
||||
}
|
||||
if (system != null) {
|
||||
system.disable();
|
||||
}
|
||||
|
@ -17,7 +17,10 @@
|
||||
package com.djrapitops.plan;
|
||||
|
||||
import com.djrapitops.plan.command.PlanCommand;
|
||||
import com.djrapitops.plan.modules.*;
|
||||
import com.djrapitops.plan.modules.APFModule;
|
||||
import com.djrapitops.plan.modules.FilesModule;
|
||||
import com.djrapitops.plan.modules.ServerSuperClassBindingModule;
|
||||
import com.djrapitops.plan.modules.SystemObjectProvidingModule;
|
||||
import com.djrapitops.plan.modules.bukkit.BukkitPlanModule;
|
||||
import com.djrapitops.plan.modules.bukkit.BukkitServerPropertiesModule;
|
||||
import com.djrapitops.plan.modules.bukkit.BukkitSuperClassBindingModule;
|
||||
@ -36,7 +39,6 @@ import javax.inject.Singleton;
|
||||
@Singleton
|
||||
@Component(modules = {
|
||||
BukkitPlanModule.class,
|
||||
SuperClassBindingModule.class,
|
||||
SystemObjectProvidingModule.class,
|
||||
APFModule.class,
|
||||
FilesModule.class,
|
||||
@ -51,6 +53,8 @@ public interface PlanBukkitComponent {
|
||||
|
||||
PlanSystem system();
|
||||
|
||||
ServerShutdownSave serverShutdownSave();
|
||||
|
||||
@Component.Builder
|
||||
interface Builder {
|
||||
|
||||
|
@ -16,6 +16,8 @@
|
||||
*/
|
||||
package com.djrapitops.plan.modules.bukkit;
|
||||
|
||||
import com.djrapitops.plan.BukkitServerShutdownSave;
|
||||
import com.djrapitops.plan.ServerShutdownSave;
|
||||
import com.djrapitops.plan.system.database.BukkitDBSystem;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.importing.BukkitImportSystem;
|
||||
@ -55,6 +57,9 @@ public interface BukkitSuperClassBindingModule {
|
||||
ListenerSystem bindBukkitListenerSystem(BukkitListenerSystem bukkitListenerSystem);
|
||||
|
||||
@Binds
|
||||
ImportSystem bindImportSsytem(BukkitImportSystem bukkitImportSystem);
|
||||
ImportSystem bindImportSystem(BukkitImportSystem bukkitImportSystem);
|
||||
|
||||
@Binds
|
||||
ServerShutdownSave bindBukkitServerShutdownSave(BukkitServerShutdownSave bukkitServerShutdownSave);
|
||||
|
||||
}
|
@ -17,9 +17,9 @@
|
||||
package com.djrapitops.plan.system.database;
|
||||
|
||||
import com.djrapitops.plan.api.exceptions.EnableException;
|
||||
import com.djrapitops.plan.system.database.databases.sql.H2DB;
|
||||
import com.djrapitops.plan.system.database.databases.sql.MySQLDB;
|
||||
import com.djrapitops.plan.system.database.databases.sql.SQLiteDB;
|
||||
import com.djrapitops.plan.db.H2DB;
|
||||
import com.djrapitops.plan.db.MySQLDB;
|
||||
import com.djrapitops.plan.db.SQLiteDB;
|
||||
import com.djrapitops.plan.system.locale.Locale;
|
||||
import com.djrapitops.plan.system.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.system.settings.paths.DatabaseSettings;
|
||||
|
@ -21,19 +21,20 @@ import com.djrapitops.plan.system.DebugChannels;
|
||||
import com.djrapitops.plugin.api.utility.UUIDFetcher;
|
||||
import com.djrapitops.plugin.benchmarking.Timings;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.World;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* A class for refining the {@link UserImportData}s
|
||||
* so no {@code null} is left in any field.
|
||||
* It also removes invalid data.
|
||||
* UserImportRefiner attempts to find any crucial information that is missing.
|
||||
*
|
||||
* - Finds UUIDs if only name is present.
|
||||
* - Finds Names if only UUID is present.
|
||||
* - Removes any importers that do not have any identifiers.
|
||||
*
|
||||
* @author Fuzzlemann
|
||||
*/
|
||||
public class UserImportRefiner {
|
||||
public class BukkitUserImportRefiner {
|
||||
|
||||
private final Plan plugin;
|
||||
private final Timings timings;
|
||||
@ -41,15 +42,13 @@ public class UserImportRefiner {
|
||||
|
||||
private final List<UserImportData> importers = new ArrayList<>();
|
||||
|
||||
private final Map<String, Boolean> worlds = new HashMap<>();
|
||||
|
||||
private final Map<UserImportData, String> uuidsMissing = new HashMap<>();
|
||||
private final Map<UserImportData, String> namesMissing = new HashMap<>();
|
||||
private final Map<UserImportData, String> missingUUIDs = new HashMap<>();
|
||||
private final Map<UserImportData, String> missingNames = new HashMap<>();
|
||||
|
||||
private final Map<UserImportData, String> foundUUIDs = new HashMap<>();
|
||||
private final Map<UserImportData, String> foundNames = new HashMap<>();
|
||||
|
||||
public UserImportRefiner(Plan plugin, List<UserImportData> importers) {
|
||||
public BukkitUserImportRefiner(Plan plugin, List<UserImportData> importers) {
|
||||
this.plugin = plugin;
|
||||
this.timings = plugin.getTimings();
|
||||
this.importers.addAll(importers);
|
||||
@ -62,44 +61,11 @@ public class UserImportRefiner {
|
||||
|
||||
timings.start(benchmarkName);
|
||||
processMissingIdentifiers();
|
||||
processOldWorlds();
|
||||
timings.end(DebugChannels.IMPORTING, benchmarkName);
|
||||
|
||||
return importers;
|
||||
}
|
||||
|
||||
private void processOldWorlds() {
|
||||
String benchmarkName = "Processing old worlds";
|
||||
|
||||
timings.start(benchmarkName);
|
||||
|
||||
importers.parallelStream()
|
||||
.flatMap(importer -> importer.getWorldTimes().keySet().stream())
|
||||
.forEach(this::checkOldWorld);
|
||||
|
||||
if (!worlds.containsValue(true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
worlds.values().removeIf(old -> false);
|
||||
|
||||
importers.parallelStream()
|
||||
.forEach(importer -> importer.getWorldTimes().keySet().removeAll(worlds.keySet()));
|
||||
|
||||
timings.end(DebugChannels.IMPORTING, benchmarkName);
|
||||
}
|
||||
|
||||
private void checkOldWorld(String worldName) {
|
||||
if (worlds.containsKey(worldName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
World world = plugin.getServer().getWorld(worldName);
|
||||
boolean old = world == null;
|
||||
|
||||
worlds.put(worldName, old);
|
||||
}
|
||||
|
||||
private void processMissingIdentifiers() {
|
||||
String benchmarkName = "Processing missing identifiers";
|
||||
|
||||
@ -117,9 +83,9 @@ public class UserImportRefiner {
|
||||
if (nameNull && uuidNull) {
|
||||
invalidData.add(importer);
|
||||
} else if (nameNull) {
|
||||
namesMissing.put(importer, uuid.toString());
|
||||
missingNames.put(importer, uuid.toString());
|
||||
} else if (uuidNull) {
|
||||
uuidsMissing.put(importer, name);
|
||||
missingUUIDs.put(importer, name);
|
||||
}
|
||||
});
|
||||
|
||||
@ -152,13 +118,13 @@ public class UserImportRefiner {
|
||||
userImportData.setUuid(uuid);
|
||||
});
|
||||
|
||||
importers.removeAll(uuidsMissing.keySet());
|
||||
importers.removeAll(missingUUIDs.keySet());
|
||||
|
||||
timings.end(DebugChannels.IMPORTING, benchmarkName);
|
||||
}
|
||||
|
||||
private void addMissingUUIDsOverFetcher() {
|
||||
UUIDFetcher uuidFetcher = new UUIDFetcher(new ArrayList<>(uuidsMissing.values()));
|
||||
UUIDFetcher uuidFetcher = new UUIDFetcher(new ArrayList<>(missingUUIDs.values()));
|
||||
|
||||
Map<String, String> result;
|
||||
|
||||
@ -175,7 +141,7 @@ public class UserImportRefiner {
|
||||
private void addMissingUUIDsOverOfflinePlayer() {
|
||||
Map<String, String> result = new HashMap<>();
|
||||
|
||||
for (String name : uuidsMissing.values()) {
|
||||
for (String name : missingUUIDs.values()) {
|
||||
String uuid = getUuidByOfflinePlayer(name);
|
||||
|
||||
if (uuid == null) {
|
||||
@ -191,7 +157,7 @@ public class UserImportRefiner {
|
||||
private void addFoundUUIDs(Map<String, String> foundUUIDs) {
|
||||
List<UserImportData> found = new ArrayList<>();
|
||||
|
||||
uuidsMissing.entrySet().parallelStream().forEach((entry) -> {
|
||||
missingUUIDs.entrySet().parallelStream().forEach(entry -> {
|
||||
UserImportData importer = entry.getKey();
|
||||
String name = entry.getValue();
|
||||
|
||||
@ -201,7 +167,7 @@ public class UserImportRefiner {
|
||||
found.add(importer);
|
||||
});
|
||||
|
||||
uuidsMissing.keySet().removeAll(found);
|
||||
missingUUIDs.keySet().removeAll(found);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@ -220,19 +186,19 @@ public class UserImportRefiner {
|
||||
|
||||
timings.start(benchmarkNames);
|
||||
|
||||
addMissingNames();
|
||||
findMissingNames();
|
||||
|
||||
foundNames.entrySet().parallelStream().forEach(entry -> entry.getKey().setName(entry.getValue()));
|
||||
|
||||
importers.removeAll(namesMissing.keySet());
|
||||
importers.removeAll(missingNames.keySet());
|
||||
|
||||
timings.end(DebugChannels.IMPORTING, benchmarkNames);
|
||||
}
|
||||
|
||||
private void addMissingNames() {
|
||||
private void findMissingNames() {
|
||||
Map<String, String> result = new HashMap<>();
|
||||
|
||||
namesMissing.values().parallelStream().forEach(uuid -> {
|
||||
missingNames.values().parallelStream().forEach(uuid -> {
|
||||
String name = getNameByOfflinePlayer(uuid);
|
||||
|
||||
result.put(uuid, name);
|
||||
@ -244,7 +210,7 @@ public class UserImportRefiner {
|
||||
private void addFoundNames(Map<String, String> foundNames) {
|
||||
List<UserImportData> found = new ArrayList<>();
|
||||
|
||||
namesMissing.entrySet().parallelStream().forEach(entry -> {
|
||||
missingNames.entrySet().parallelStream().forEach(entry -> {
|
||||
UserImportData importer = entry.getKey();
|
||||
String uuid = entry.getValue();
|
||||
|
||||
@ -254,7 +220,7 @@ public class UserImportRefiner {
|
||||
found.add(importer);
|
||||
});
|
||||
|
||||
namesMissing.keySet().removeAll(found);
|
||||
missingNames.keySet().removeAll(found);
|
||||
}
|
||||
|
||||
private String getNameByOfflinePlayer(String uuid) {
|
@ -17,24 +17,24 @@
|
||||
package com.djrapitops.plan.system.importing.importers;
|
||||
|
||||
import com.djrapitops.plan.Plan;
|
||||
import com.djrapitops.plan.api.exceptions.database.DBException;
|
||||
import com.djrapitops.plan.api.exceptions.database.DBOpException;
|
||||
import com.djrapitops.plan.data.container.BaseUser;
|
||||
import com.djrapitops.plan.data.container.GeoInfo;
|
||||
import com.djrapitops.plan.data.container.Session;
|
||||
import com.djrapitops.plan.data.container.UserInfo;
|
||||
import com.djrapitops.plan.data.store.objects.Nickname;
|
||||
import com.djrapitops.plan.data.time.WorldTimes;
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.db.access.queries.LargeStoreQueries;
|
||||
import com.djrapitops.plan.db.access.queries.objects.UserIdentifierQueries;
|
||||
import com.djrapitops.plan.db.access.transactions.Transaction;
|
||||
import com.djrapitops.plan.system.cache.GeolocationCache;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.database.databases.operation.FetchOperations;
|
||||
import com.djrapitops.plan.system.database.databases.operation.SaveOperations;
|
||||
import com.djrapitops.plan.system.importing.data.BukkitUserImportRefiner;
|
||||
import com.djrapitops.plan.system.importing.data.ServerImportData;
|
||||
import com.djrapitops.plan.system.importing.data.UserImportData;
|
||||
import com.djrapitops.plan.system.importing.data.UserImportRefiner;
|
||||
import com.djrapitops.plan.system.info.server.ServerInfo;
|
||||
import com.djrapitops.plan.utilities.SHA256Hash;
|
||||
import com.djrapitops.plugin.utilities.Verify;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.*;
|
||||
@ -45,6 +45,8 @@ import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Generic importer for user data into Plan on the Bukkit platform.
|
||||
*
|
||||
* @author Fuzzlemann
|
||||
*/
|
||||
public abstract class BukkitImporter implements Importer {
|
||||
@ -88,17 +90,12 @@ public abstract class BukkitImporter implements Importer {
|
||||
public final void processImport() {
|
||||
ExecutorService service = Executors.newCachedThreadPool();
|
||||
|
||||
submitTo(service, this::processServerData);
|
||||
submitTo(service, this::processUserData);
|
||||
|
||||
service.shutdown();
|
||||
try {
|
||||
service.awaitTermination(20, TimeUnit.MINUTES);
|
||||
} catch (InterruptedException e) {
|
||||
service.shutdownNow();
|
||||
Thread.currentThread().interrupt();
|
||||
service.submit(this::processServerData);
|
||||
service.submit(this::processUserData);
|
||||
} finally {
|
||||
shutdownService(service);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void processServerData() {
|
||||
@ -108,19 +105,13 @@ public abstract class BukkitImporter implements Importer {
|
||||
return;
|
||||
}
|
||||
|
||||
ExecutorService service = Executors.newCachedThreadPool();
|
||||
|
||||
SaveOperations save = dbSystem.getDatabase().save();
|
||||
submitTo(service, () -> save.insertTPS(ImmutableMap.of(serverUUID.get(), serverImportData.getTpsData())));
|
||||
submitTo(service, () -> save.insertCommandUsage(ImmutableMap.of(serverUUID.get(), serverImportData.getCommandUsages())));
|
||||
|
||||
service.shutdown();
|
||||
try {
|
||||
service.awaitTermination(20, TimeUnit.MINUTES);
|
||||
} catch (InterruptedException e) {
|
||||
service.shutdownNow();
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
dbSystem.getDatabase().executeTransaction(new Transaction() {
|
||||
@Override
|
||||
protected void performOperations() {
|
||||
execute(LargeStoreQueries.storeAllTPSData(Collections.singletonMap(serverUUID.get(), serverImportData.getTpsData())));
|
||||
execute(LargeStoreQueries.storeAllCommandUsageData(Collections.singletonMap(serverUUID.get(), serverImportData.getCommandUsages())));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void processUserData() {
|
||||
@ -130,70 +121,76 @@ public abstract class BukkitImporter implements Importer {
|
||||
return;
|
||||
}
|
||||
|
||||
UserImportRefiner userImportRefiner = new UserImportRefiner(plugin, userImportData);
|
||||
BukkitUserImportRefiner userImportRefiner = new BukkitUserImportRefiner(plugin, userImportData);
|
||||
userImportData = userImportRefiner.refineData();
|
||||
|
||||
FetchOperations fetch = dbSystem.getDatabase().fetch();
|
||||
Set<UUID> existingUUIDs = fetch.getSavedUUIDs();
|
||||
Set<UUID> existingUserInfoTableUUIDs = fetch.getSavedUUIDs(serverUUID.get());
|
||||
Database db = dbSystem.getDatabase();
|
||||
|
||||
Map<UUID, UserInfo> users = new HashMap<>();
|
||||
Set<UUID> existingUUIDs = db.query(UserIdentifierQueries.fetchAllPlayerUUIDs());
|
||||
Set<UUID> existingUserInfoTableUUIDs = db.query(UserIdentifierQueries.fetchPlayerUUIDsOfServer(serverUUID.get()));
|
||||
|
||||
Map<UUID, BaseUser> users = new HashMap<>();
|
||||
List<UserInfo> userInfo = new ArrayList<>();
|
||||
Map<UUID, List<Nickname>> nickNames = new HashMap<>();
|
||||
Map<UUID, List<Session>> sessions = new HashMap<>();
|
||||
List<Session> sessions = new ArrayList<>();
|
||||
Map<UUID, List<GeoInfo>> geoInfo = new HashMap<>();
|
||||
Map<UUID, Integer> timesKicked = new HashMap<>();
|
||||
|
||||
userImportData.parallelStream().forEach(data -> {
|
||||
UUID uuid = data.getUuid();
|
||||
UserInfo info = toUserInfo(data);
|
||||
|
||||
if (!existingUUIDs.contains(uuid)) {
|
||||
users.put(uuid, info);
|
||||
users.put(uuid, toBaseUser(data));
|
||||
}
|
||||
|
||||
if (!existingUserInfoTableUUIDs.contains(uuid)) {
|
||||
userInfo.add(info);
|
||||
userInfo.add(toUserInfo(data));
|
||||
}
|
||||
|
||||
nickNames.put(uuid, data.getNicknames());
|
||||
geoInfo.put(uuid, convertGeoInfo(data));
|
||||
timesKicked.put(uuid, data.getTimesKicked());
|
||||
sessions.put(uuid, Collections.singletonList(toSession(data)));
|
||||
sessions.add(toSession(data));
|
||||
});
|
||||
|
||||
ExecutorService service = Executors.newCachedThreadPool();
|
||||
|
||||
SaveOperations save = dbSystem.getDatabase().save();
|
||||
|
||||
save.insertUsers(users);
|
||||
submitTo(service, () -> save.insertSessions(ImmutableMap.of(serverUUID.get(), sessions), true));
|
||||
submitTo(service, () -> save.kickAmount(timesKicked));
|
||||
submitTo(service, () -> save.insertUserInfo(ImmutableMap.of(serverUUID.get(), userInfo)));
|
||||
submitTo(service, () -> save.insertNicknames(ImmutableMap.of(serverUUID.get(), nickNames)));
|
||||
submitTo(service, () -> save.insertAllGeoInfo(geoInfo));
|
||||
db.executeTransaction(new Transaction() {
|
||||
@Override
|
||||
protected void performOperations() {
|
||||
execute(LargeStoreQueries.storeAllCommonUserInformation(users.values()));
|
||||
execute(LargeStoreQueries.storeAllSessionsWithKillAndWorldData(sessions));
|
||||
Map<UUID, List<UserInfo>> userInformation = Collections.singletonMap(serverUUID.get(), userInfo);
|
||||
execute(LargeStoreQueries.storePerServerUserInformation(userInformation));
|
||||
execute(LargeStoreQueries.storeAllNicknameData(Collections.singletonMap(serverUUID.get(), nickNames)));
|
||||
execute(LargeStoreQueries.storeAllGeoInformation(geoInfo));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void shutdownService(ExecutorService service) {
|
||||
service.shutdown();
|
||||
try {
|
||||
service.awaitTermination(20, TimeUnit.MINUTES);
|
||||
if (!service.awaitTermination(20, TimeUnit.MINUTES)) {
|
||||
service.shutdownNow();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
service.shutdownNow();
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
private void submitTo(ExecutorService service, ImportExecutorHelper helper) {
|
||||
helper.submit(service);
|
||||
private BaseUser toBaseUser(UserImportData userImportData) {
|
||||
UUID uuid = userImportData.getUuid();
|
||||
String name = userImportData.getName();
|
||||
long registered = userImportData.getRegistered();
|
||||
int timesKicked = userImportData.getTimesKicked();
|
||||
return new BaseUser(uuid, name, registered, timesKicked);
|
||||
}
|
||||
|
||||
private UserInfo toUserInfo(UserImportData userImportData) {
|
||||
UUID uuid = userImportData.getUuid();
|
||||
String name = userImportData.getName();
|
||||
long registered = userImportData.getRegistered();
|
||||
boolean op = userImportData.isOp();
|
||||
boolean banned = userImportData.isBanned();
|
||||
|
||||
return new UserInfo(uuid, name, registered, op, banned);
|
||||
return new UserInfo(uuid, serverUUID.get(), registered, op, banned);
|
||||
}
|
||||
|
||||
private Session toSession(UserImportData userImportData) {
|
||||
@ -221,18 +218,4 @@ public abstract class BukkitImporter implements Importer {
|
||||
}
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private interface ImportExecutorHelper {
|
||||
void execute() throws DBException;
|
||||
|
||||
default void submit(ExecutorService service) {
|
||||
service.submit(() -> {
|
||||
try {
|
||||
execute();
|
||||
} catch (DBException e) {
|
||||
throw new DBOpException("Import Execution failed", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,8 +16,11 @@
|
||||
*/
|
||||
package com.djrapitops.plan.system.listeners.bukkit;
|
||||
|
||||
import com.djrapitops.plan.system.processing.Processing;
|
||||
import com.djrapitops.plan.system.processing.processors.player.PlayerProcessors;
|
||||
import com.djrapitops.plan.data.store.objects.Nickname;
|
||||
import com.djrapitops.plan.db.access.transactions.events.NicknameStoreTransaction;
|
||||
import com.djrapitops.plan.system.cache.NicknameCache;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.info.server.ServerInfo;
|
||||
import com.djrapitops.plugin.logging.L;
|
||||
import com.djrapitops.plugin.logging.error.ErrorHandler;
|
||||
import org.bukkit.entity.Player;
|
||||
@ -36,18 +39,21 @@ import java.util.UUID;
|
||||
*/
|
||||
public class ChatListener implements Listener {
|
||||
|
||||
private final PlayerProcessors processorFactory;
|
||||
private final Processing processing;
|
||||
private final ServerInfo serverInfo;
|
||||
private final DBSystem dbSystem;
|
||||
private final NicknameCache nicknameCache;
|
||||
private final ErrorHandler errorHandler;
|
||||
|
||||
@Inject
|
||||
public ChatListener(
|
||||
PlayerProcessors processorFactory,
|
||||
Processing processing,
|
||||
ServerInfo serverInfo,
|
||||
DBSystem dbSystem,
|
||||
NicknameCache nicknameCache,
|
||||
ErrorHandler errorHandler
|
||||
) {
|
||||
this.processorFactory = processorFactory;
|
||||
this.processing = processing;
|
||||
this.serverInfo = serverInfo;
|
||||
this.dbSystem = dbSystem;
|
||||
this.nicknameCache = nicknameCache;
|
||||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
@ -65,10 +71,14 @@ public class ChatListener implements Listener {
|
||||
}
|
||||
|
||||
private void actOnChatEvent(AsyncPlayerChatEvent event) {
|
||||
Player p = event.getPlayer();
|
||||
UUID uuid = p.getUniqueId();
|
||||
String name = p.getName();
|
||||
String displayName = p.getDisplayName();
|
||||
processing.submit(processorFactory.nameProcessor(uuid, name, displayName));
|
||||
long time = System.currentTimeMillis();
|
||||
Player player = event.getPlayer();
|
||||
UUID uuid = player.getUniqueId();
|
||||
String displayName = player.getDisplayName();
|
||||
|
||||
dbSystem.getDatabase().executeTransaction(new NicknameStoreTransaction(
|
||||
uuid, new Nickname(displayName, time, serverInfo.getServerUUID()),
|
||||
(playerUUID, name) -> name.equals(nicknameCache.getDisplayName(playerUUID))
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -17,8 +17,9 @@
|
||||
package com.djrapitops.plan.system.listeners.bukkit;
|
||||
|
||||
import com.djrapitops.plan.Plan;
|
||||
import com.djrapitops.plan.system.processing.Processing;
|
||||
import com.djrapitops.plan.system.processing.processors.Processors;
|
||||
import com.djrapitops.plan.db.access.transactions.events.CommandStoreTransaction;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.info.server.ServerInfo;
|
||||
import com.djrapitops.plan.system.settings.Permissions;
|
||||
import com.djrapitops.plan.system.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.system.settings.paths.DataGatheringSettings;
|
||||
@ -41,22 +42,22 @@ public class CommandListener implements Listener {
|
||||
|
||||
private final Plan plugin;
|
||||
private final PlanConfig config;
|
||||
private final Processors processors;
|
||||
private final Processing processing;
|
||||
private final ServerInfo serverInfo;
|
||||
private final DBSystem dbSystem;
|
||||
private final ErrorHandler errorHandler;
|
||||
|
||||
@Inject
|
||||
public CommandListener(
|
||||
Plan plugin,
|
||||
PlanConfig config,
|
||||
Processors processors,
|
||||
Processing processing,
|
||||
ServerInfo serverInfo,
|
||||
DBSystem dbSystem,
|
||||
ErrorHandler errorHandler
|
||||
) {
|
||||
this.plugin = plugin;
|
||||
this.config = config;
|
||||
this.processors = processors;
|
||||
this.processing = processing;
|
||||
this.serverInfo = serverInfo;
|
||||
this.dbSystem = dbSystem;
|
||||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
@ -90,7 +91,7 @@ public class CommandListener implements Listener {
|
||||
commandName = command.getName();
|
||||
}
|
||||
}
|
||||
processing.submit(processors.commandProcessor(commandName));
|
||||
dbSystem.getDatabase().executeTransaction(new CommandStoreTransaction(serverInfo.getServerUUID(), commandName));
|
||||
}
|
||||
|
||||
private Command getBukkitCommand(String commandName) {
|
||||
|
@ -17,7 +17,10 @@
|
||||
package com.djrapitops.plan.system.listeners.bukkit;
|
||||
|
||||
import com.djrapitops.plan.data.container.Session;
|
||||
import com.djrapitops.plan.db.access.transactions.events.WorldNameStoreTransaction;
|
||||
import com.djrapitops.plan.system.cache.SessionCache;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.info.server.ServerInfo;
|
||||
import com.djrapitops.plan.system.settings.config.WorldAliasSettings;
|
||||
import com.djrapitops.plugin.logging.L;
|
||||
import com.djrapitops.plugin.logging.error.ErrorHandler;
|
||||
@ -39,14 +42,20 @@ import java.util.UUID;
|
||||
public class GameModeChangeListener implements Listener {
|
||||
|
||||
private final WorldAliasSettings worldAliasSettings;
|
||||
private final ServerInfo serverInfo;
|
||||
private final DBSystem dbSystem;
|
||||
private final ErrorHandler errorHandler;
|
||||
|
||||
@Inject
|
||||
public GameModeChangeListener(
|
||||
WorldAliasSettings worldAliasSettings,
|
||||
ServerInfo serverInfo,
|
||||
DBSystem dbSystem,
|
||||
ErrorHandler errorHandler
|
||||
) {
|
||||
this.worldAliasSettings = worldAliasSettings;
|
||||
this.serverInfo = serverInfo;
|
||||
this.dbSystem = dbSystem;
|
||||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
@ -69,6 +78,7 @@ public class GameModeChangeListener implements Listener {
|
||||
String gameMode = event.getNewGameMode().name();
|
||||
String worldName = player.getWorld().getName();
|
||||
|
||||
dbSystem.getDatabase().executeTransaction(new WorldNameStoreTransaction(serverInfo.getServerUUID(), worldName));
|
||||
worldAliasSettings.addWorld(worldName);
|
||||
|
||||
Optional<Session> cachedSession = SessionCache.getCachedSession(uuid);
|
||||
|
@ -17,7 +17,13 @@
|
||||
package com.djrapitops.plan.system.listeners.bukkit;
|
||||
|
||||
import com.djrapitops.plan.data.container.Session;
|
||||
import com.djrapitops.plan.data.store.objects.Nickname;
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.db.access.transactions.events.*;
|
||||
import com.djrapitops.plan.system.cache.GeolocationCache;
|
||||
import com.djrapitops.plan.system.cache.NicknameCache;
|
||||
import com.djrapitops.plan.system.cache.SessionCache;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.info.server.ServerInfo;
|
||||
import com.djrapitops.plan.system.processing.Processing;
|
||||
import com.djrapitops.plan.system.processing.processors.Processors;
|
||||
@ -26,7 +32,6 @@ import com.djrapitops.plan.system.settings.paths.DataGatheringSettings;
|
||||
import com.djrapitops.plan.system.status.Status;
|
||||
import com.djrapitops.plugin.logging.L;
|
||||
import com.djrapitops.plugin.logging.error.ErrorHandler;
|
||||
import com.djrapitops.plugin.task.RunnableFactory;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
@ -51,10 +56,12 @@ public class PlayerOnlineListener implements Listener {
|
||||
private final Processors processors;
|
||||
private final Processing processing;
|
||||
private final ServerInfo serverInfo;
|
||||
private final DBSystem dbSystem;
|
||||
private final GeolocationCache geolocationCache;
|
||||
private final NicknameCache nicknameCache;
|
||||
private final SessionCache sessionCache;
|
||||
private final ErrorHandler errorHandler;
|
||||
private final Status status;
|
||||
private final RunnableFactory runnableFactory;
|
||||
|
||||
@Inject
|
||||
public PlayerOnlineListener(
|
||||
@ -62,18 +69,22 @@ public class PlayerOnlineListener implements Listener {
|
||||
Processors processors,
|
||||
Processing processing,
|
||||
ServerInfo serverInfo,
|
||||
DBSystem dbSystem,
|
||||
GeolocationCache geolocationCache,
|
||||
NicknameCache nicknameCache,
|
||||
SessionCache sessionCache,
|
||||
Status status,
|
||||
RunnableFactory runnableFactory,
|
||||
ErrorHandler errorHandler
|
||||
) {
|
||||
this.config = config;
|
||||
this.processors = processors;
|
||||
this.processing = processing;
|
||||
this.serverInfo = serverInfo;
|
||||
this.dbSystem = dbSystem;
|
||||
this.geolocationCache = geolocationCache;
|
||||
this.nicknameCache = nicknameCache;
|
||||
this.sessionCache = sessionCache;
|
||||
this.status = status;
|
||||
this.runnableFactory = runnableFactory;
|
||||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
@ -81,10 +92,11 @@ public class PlayerOnlineListener implements Listener {
|
||||
public void onPlayerLogin(PlayerLoginEvent event) {
|
||||
try {
|
||||
PlayerLoginEvent.Result result = event.getResult();
|
||||
UUID uuid = event.getPlayer().getUniqueId();
|
||||
boolean op = event.getPlayer().isOp();
|
||||
UUID playerUUID = event.getPlayer().getUniqueId();
|
||||
boolean operator = event.getPlayer().isOp();
|
||||
boolean banned = result == PlayerLoginEvent.Result.KICK_BANNED;
|
||||
processing.submit(processors.player().banAndOpProcessor(uuid, () -> banned, op));
|
||||
dbSystem.getDatabase().executeTransaction(new BanStatusTransaction(playerUUID, () -> banned));
|
||||
dbSystem.getDatabase().executeTransaction(new OperatorStatusTransaction(playerUUID, operator));
|
||||
} catch (Exception e) {
|
||||
errorHandler.log(L.ERROR, this.getClass(), e);
|
||||
}
|
||||
@ -109,7 +121,7 @@ public class PlayerOnlineListener implements Listener {
|
||||
return;
|
||||
}
|
||||
|
||||
processing.submit(processors.player().kickProcessor(uuid));
|
||||
dbSystem.getDatabase().executeTransaction(new KickStoreTransaction(uuid));
|
||||
} catch (Exception e) {
|
||||
errorHandler.log(L.ERROR, this.getClass(), e);
|
||||
}
|
||||
@ -126,9 +138,9 @@ public class PlayerOnlineListener implements Listener {
|
||||
|
||||
private void actOnJoinEvent(PlayerJoinEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
// TODO Move update notification to the website.
|
||||
|
||||
UUID uuid = player.getUniqueId();
|
||||
UUID serverUUID = serverInfo.getServerUUID();
|
||||
long time = System.currentTimeMillis();
|
||||
|
||||
AFKListener.AFK_TRACKER.performedAction(uuid, time);
|
||||
@ -136,21 +148,32 @@ public class PlayerOnlineListener implements Listener {
|
||||
String world = player.getWorld().getName();
|
||||
String gm = player.getGameMode().name();
|
||||
|
||||
Database database = dbSystem.getDatabase();
|
||||
database.executeTransaction(new WorldNameStoreTransaction(serverUUID, world));
|
||||
|
||||
InetAddress address = player.getAddress().getAddress();
|
||||
|
||||
String playerName = player.getName();
|
||||
String displayName = player.getDisplayName();
|
||||
|
||||
boolean gatheringGeolocations = config.isTrue(DataGatheringSettings.GEOLOCATIONS);
|
||||
if (gatheringGeolocations) {
|
||||
database.executeTransaction(
|
||||
new GeoInfoStoreTransaction(uuid, address, time, geolocationCache::getCountry)
|
||||
);
|
||||
}
|
||||
|
||||
database.executeTransaction(new PlayerServerRegisterTransaction(uuid, player::getFirstPlayed, playerName, serverUUID));
|
||||
sessionCache.cacheSession(uuid, new Session(uuid, serverUUID, time, world, gm))
|
||||
.ifPresent(previousSession -> database.executeTransaction(new SessionEndTransaction(previousSession)));
|
||||
|
||||
database.executeTransaction(new NicknameStoreTransaction(
|
||||
uuid, new Nickname(displayName, time, serverUUID),
|
||||
(playerUUID, name) -> name.equals(nicknameCache.getDisplayName(playerUUID))
|
||||
));
|
||||
|
||||
processing.submitNonCritical(processors.info().playerPageUpdateProcessor(uuid));
|
||||
|
||||
processing.submitCritical(() -> sessionCache.cacheSession(uuid, new Session(uuid, serverInfo.getServerUUID(), time, world, gm)));
|
||||
runnableFactory.create("Player Register: " + uuid,
|
||||
processors.player().registerProcessor(uuid, player::getFirstPlayed, playerName,
|
||||
gatheringGeolocations ? processors.player().ipUpdateProcessor(uuid, address, time) : null,
|
||||
processors.player().nameProcessor(uuid, playerName, displayName),
|
||||
processors.info().playerPageUpdateProcessor(uuid)
|
||||
)
|
||||
).runTaskAsynchronously();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
@ -165,12 +188,17 @@ public class PlayerOnlineListener implements Listener {
|
||||
private void actOnQuitEvent(PlayerQuitEvent event) {
|
||||
long time = System.currentTimeMillis();
|
||||
Player player = event.getPlayer();
|
||||
UUID uuid = player.getUniqueId();
|
||||
UUID playerUUID = player.getUniqueId();
|
||||
|
||||
AFKListener.AFK_TRACKER.loggedOut(uuid, time);
|
||||
AFKListener.AFK_TRACKER.loggedOut(playerUUID, time);
|
||||
|
||||
processing.submit(processors.player().banAndOpProcessor(uuid, player::isBanned, player.isOp()));
|
||||
processing.submit(processors.player().endSessionProcessor(uuid, time));
|
||||
processing.submit(processors.info().playerPageUpdateProcessor(uuid));
|
||||
nicknameCache.removeDisplayName(playerUUID);
|
||||
|
||||
dbSystem.getDatabase().executeTransaction(new BanStatusTransaction(playerUUID, player::isBanned));
|
||||
|
||||
sessionCache.endSession(playerUUID, time)
|
||||
.ifPresent(endedSession -> dbSystem.getDatabase().executeTransaction(new SessionEndTransaction(endedSession)));
|
||||
|
||||
processing.submit(processors.info().playerPageUpdateProcessor(playerUUID));
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,10 @@
|
||||
package com.djrapitops.plan.system.listeners.bukkit;
|
||||
|
||||
import com.djrapitops.plan.data.container.Session;
|
||||
import com.djrapitops.plan.db.access.transactions.events.WorldNameStoreTransaction;
|
||||
import com.djrapitops.plan.system.cache.SessionCache;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.info.server.ServerInfo;
|
||||
import com.djrapitops.plan.system.settings.config.WorldAliasSettings;
|
||||
import com.djrapitops.plugin.logging.L;
|
||||
import com.djrapitops.plugin.logging.error.ErrorHandler;
|
||||
@ -34,14 +37,20 @@ import java.util.UUID;
|
||||
public class WorldChangeListener implements Listener {
|
||||
|
||||
private final WorldAliasSettings worldAliasSettings;
|
||||
private final ServerInfo serverInfo;
|
||||
private final DBSystem dbSystem;
|
||||
private final ErrorHandler errorHandler;
|
||||
|
||||
@Inject
|
||||
public WorldChangeListener(
|
||||
WorldAliasSettings worldAliasSettings,
|
||||
ServerInfo serverInfo,
|
||||
DBSystem dbSystem,
|
||||
ErrorHandler errorHandler
|
||||
) {
|
||||
this.worldAliasSettings = worldAliasSettings;
|
||||
this.serverInfo = serverInfo;
|
||||
this.dbSystem = dbSystem;
|
||||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
@ -63,6 +72,7 @@ public class WorldChangeListener implements Listener {
|
||||
String worldName = player.getWorld().getName();
|
||||
String gameMode = player.getGameMode().name();
|
||||
|
||||
dbSystem.getDatabase().executeTransaction(new WorldNameStoreTransaction(serverInfo.getServerUUID(), worldName));
|
||||
worldAliasSettings.addWorld(worldName);
|
||||
|
||||
Optional<Session> cachedSession = SessionCache.getCachedSession(uuid);
|
||||
|
@ -18,6 +18,7 @@ package com.djrapitops.plan.system.tasks;
|
||||
|
||||
import com.djrapitops.plan.Plan;
|
||||
import com.djrapitops.plan.ShutdownHook;
|
||||
import com.djrapitops.plan.db.tasks.DBCleanTask;
|
||||
import com.djrapitops.plan.system.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.system.settings.paths.TimeSettings;
|
||||
import com.djrapitops.plan.system.tasks.bukkit.BukkitTPSCountTimer;
|
||||
@ -32,6 +33,7 @@ import com.djrapitops.plugin.task.RunnableFactory;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@ -40,12 +42,14 @@ import java.util.concurrent.TimeUnit;
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Singleton
|
||||
public class BukkitTaskSystem extends ServerTaskSystem {
|
||||
|
||||
private final Plan plugin;
|
||||
private final ShutdownHook shutdownHook;
|
||||
private final PingCountTimerBukkit pingCountTimer;
|
||||
private final ConfigStoreTask configStoreTask;
|
||||
private final DBCleanTask dbCleanTask;
|
||||
|
||||
@Inject
|
||||
public BukkitTaskSystem(
|
||||
@ -60,7 +64,8 @@ public class BukkitTaskSystem extends ServerTaskSystem {
|
||||
PingCountTimerBukkit pingCountTimer,
|
||||
LogsFolderCleanTask logsFolderCleanTask,
|
||||
PlayersPageRefreshTask playersPageRefreshTask,
|
||||
ConfigStoreTask configStoreTask
|
||||
ConfigStoreTask configStoreTask,
|
||||
DBCleanTask dbCleanTask
|
||||
) {
|
||||
super(
|
||||
runnableFactory,
|
||||
@ -74,6 +79,7 @@ public class BukkitTaskSystem extends ServerTaskSystem {
|
||||
this.shutdownHook = shutdownHook;
|
||||
this.pingCountTimer = pingCountTimer;
|
||||
this.configStoreTask = configStoreTask;
|
||||
this.dbCleanTask = dbCleanTask;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -88,6 +94,11 @@ public class BukkitTaskSystem extends ServerTaskSystem {
|
||||
// +40 ticks / 2 seconds so that update check task runs first.
|
||||
long storeDelay = TimeAmount.toTicks(config.get(TimeSettings.CONFIG_UPDATE_INTERVAL), TimeUnit.MILLISECONDS) + 40;
|
||||
registerTask("Config Store Task", configStoreTask).runTaskLaterAsynchronously(storeDelay);
|
||||
|
||||
registerTask("DB Clean Task", dbCleanTask).runTaskTimerAsynchronously(
|
||||
TimeAmount.toTicks(20, TimeUnit.SECONDS),
|
||||
TimeAmount.toTicks(config.get(TimeSettings.CLEAN_DATABASE_PERIOD), TimeUnit.MILLISECONDS)
|
||||
);
|
||||
} catch (ExceptionInInitializerError | NoClassDefFoundError ignore) {
|
||||
// Running CraftBukkit
|
||||
}
|
||||
|
@ -19,9 +19,9 @@ package com.djrapitops.plan.system.tasks.bukkit;
|
||||
import com.djrapitops.plan.Plan;
|
||||
import com.djrapitops.plan.data.container.TPS;
|
||||
import com.djrapitops.plan.data.container.builders.TPSBuilder;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.info.server.ServerInfo;
|
||||
import com.djrapitops.plan.system.info.server.properties.ServerProperties;
|
||||
import com.djrapitops.plan.system.processing.Processing;
|
||||
import com.djrapitops.plan.system.processing.processors.Processors;
|
||||
import com.djrapitops.plan.system.tasks.TPSCountTimer;
|
||||
import com.djrapitops.plugin.logging.console.PluginLogger;
|
||||
import com.djrapitops.plugin.logging.error.ErrorHandler;
|
||||
@ -41,13 +41,13 @@ public class BukkitTPSCountTimer extends TPSCountTimer {
|
||||
@Inject
|
||||
public BukkitTPSCountTimer(
|
||||
Plan plugin,
|
||||
Processors processors,
|
||||
Processing processing,
|
||||
DBSystem dbSystem,
|
||||
ServerInfo serverInfo,
|
||||
ServerProperties serverProperties,
|
||||
PluginLogger logger,
|
||||
ErrorHandler errorHandler
|
||||
) {
|
||||
super(processors, processing, logger, errorHandler);
|
||||
super(dbSystem, serverInfo, logger, errorHandler);
|
||||
this.plugin = plugin;
|
||||
this.serverProperties = serverProperties;
|
||||
lastCheckNano = -1;
|
||||
|
@ -19,9 +19,8 @@ package com.djrapitops.plan.system.tasks.bukkit;
|
||||
import com.djrapitops.plan.Plan;
|
||||
import com.djrapitops.plan.data.container.TPS;
|
||||
import com.djrapitops.plan.data.container.builders.TPSBuilder;
|
||||
import com.djrapitops.plan.system.info.server.properties.ServerProperties;
|
||||
import com.djrapitops.plan.system.processing.Processing;
|
||||
import com.djrapitops.plan.system.processing.processors.Processors;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.info.server.ServerInfo;
|
||||
import com.djrapitops.plugin.logging.console.PluginLogger;
|
||||
import com.djrapitops.plugin.logging.error.ErrorHandler;
|
||||
import org.bukkit.World;
|
||||
@ -33,13 +32,12 @@ public class PaperTPSCountTimer extends BukkitTPSCountTimer {
|
||||
@Inject
|
||||
public PaperTPSCountTimer(
|
||||
Plan plugin,
|
||||
Processors processors,
|
||||
Processing processing,
|
||||
ServerProperties serverProperties,
|
||||
DBSystem dbSystem,
|
||||
ServerInfo serverInfo,
|
||||
PluginLogger logger,
|
||||
ErrorHandler errorHandler
|
||||
) {
|
||||
super(plugin, processors, processing, serverProperties, logger, errorHandler);
|
||||
super(plugin, dbSystem, serverInfo, serverInfo.getServerProperties(), logger, errorHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -24,8 +24,9 @@
|
||||
package com.djrapitops.plan.system.tasks.bukkit;
|
||||
|
||||
import com.djrapitops.plan.data.store.objects.DateObj;
|
||||
import com.djrapitops.plan.system.processing.Processing;
|
||||
import com.djrapitops.plan.system.processing.processors.Processors;
|
||||
import com.djrapitops.plan.db.access.transactions.events.PingStoreTransaction;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.info.server.ServerInfo;
|
||||
import com.djrapitops.plan.system.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.system.settings.paths.TimeSettings;
|
||||
import com.djrapitops.plan.utilities.java.Reflection;
|
||||
@ -107,20 +108,20 @@ public class PingCountTimerBukkit extends AbsRunnable implements Listener {
|
||||
private final Map<UUID, List<DateObj<Integer>>> playerHistory;
|
||||
|
||||
private final PlanConfig config;
|
||||
private final Processors processors;
|
||||
private final Processing processing;
|
||||
private final DBSystem dbSystem;
|
||||
private final ServerInfo serverInfo;
|
||||
private final RunnableFactory runnableFactory;
|
||||
|
||||
@Inject
|
||||
public PingCountTimerBukkit(
|
||||
PlanConfig config,
|
||||
Processors processors,
|
||||
Processing processing,
|
||||
DBSystem dbSystem,
|
||||
ServerInfo serverInfo,
|
||||
RunnableFactory runnableFactory
|
||||
) {
|
||||
this.config = config;
|
||||
this.processors = processors;
|
||||
this.processing = processing;
|
||||
this.dbSystem = dbSystem;
|
||||
this.serverInfo = serverInfo;
|
||||
this.runnableFactory = runnableFactory;
|
||||
playerHistory = new HashMap<>();
|
||||
}
|
||||
@ -153,7 +154,9 @@ public class PingCountTimerBukkit extends AbsRunnable implements Listener {
|
||||
}
|
||||
history.add(new DateObj<>(time, ping));
|
||||
if (history.size() >= 30) {
|
||||
processing.submit(processors.player().pingInsertProcessor(uuid, new ArrayList<>(history)));
|
||||
dbSystem.getDatabase().executeTransaction(
|
||||
new PingStoreTransaction(uuid, serverInfo.getServerUUID(), new ArrayList<>(history))
|
||||
);
|
||||
history.clear();
|
||||
}
|
||||
} else {
|
||||
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
package com.djrapitops.plan;
|
||||
|
||||
import com.djrapitops.plan.system.database.databases.Database;
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.system.info.connection.ConnectionSystem;
|
||||
import org.bstats.bungeecord.Metrics;
|
||||
|
||||
@ -49,7 +49,7 @@ public class BStatsBungee {
|
||||
|
||||
addStringSettingPie("server_type", serverType);
|
||||
addStringSettingPie("database_type", databaseType);
|
||||
addStringSettingPie("network_servers", connectionSystem.getBukkitServers().size());
|
||||
addStringSettingPie("network_servers", connectionSystem.getDataServers().size());
|
||||
}
|
||||
|
||||
protected void addStringSettingPie(String id, Serializable setting) {
|
||||
|
@ -17,7 +17,10 @@
|
||||
package com.djrapitops.plan;
|
||||
|
||||
import com.djrapitops.plan.command.PlanProxyCommand;
|
||||
import com.djrapitops.plan.modules.*;
|
||||
import com.djrapitops.plan.modules.APFModule;
|
||||
import com.djrapitops.plan.modules.FilesModule;
|
||||
import com.djrapitops.plan.modules.ProxySuperClassBindingModule;
|
||||
import com.djrapitops.plan.modules.SystemObjectProvidingModule;
|
||||
import com.djrapitops.plan.modules.bungee.BungeeCommandModule;
|
||||
import com.djrapitops.plan.modules.bungee.BungeePlanModule;
|
||||
import com.djrapitops.plan.modules.bungee.BungeeServerPropertiesModule;
|
||||
@ -38,7 +41,6 @@ import javax.inject.Singleton;
|
||||
@Component(modules = {
|
||||
BungeePlanModule.class,
|
||||
BungeeCommandModule.class,
|
||||
SuperClassBindingModule.class,
|
||||
SystemObjectProvidingModule.class,
|
||||
APFModule.class,
|
||||
FilesModule.class,
|
||||
|
@ -18,8 +18,10 @@ package com.djrapitops.plan.system.info.server;
|
||||
|
||||
import com.djrapitops.plan.api.exceptions.EnableException;
|
||||
import com.djrapitops.plan.api.exceptions.database.DBOpException;
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.db.access.queries.objects.ServerQueries;
|
||||
import com.djrapitops.plan.db.access.transactions.StoreServerInformationTransaction;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.database.databases.Database;
|
||||
import com.djrapitops.plan.system.info.server.properties.ServerProperties;
|
||||
import com.djrapitops.plan.system.webserver.WebServer;
|
||||
import com.djrapitops.plugin.logging.console.PluginLogger;
|
||||
@ -29,6 +31,7 @@ import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
/**
|
||||
* Manages Server information on the Bungee instance.
|
||||
@ -61,15 +64,17 @@ public class BungeeServerInfo extends ServerInfo {
|
||||
|
||||
try {
|
||||
Database database = dbSystem.getDatabase();
|
||||
Optional<Server> bungeeInfo = database.fetch().getBungeeInformation();
|
||||
if (bungeeInfo.isPresent()) {
|
||||
server = bungeeInfo.get();
|
||||
Optional<Server> proxyInfo = database.query(ServerQueries.fetchProxyServerInformation());
|
||||
if (proxyInfo.isPresent()) {
|
||||
server = proxyInfo.get();
|
||||
updateServerInfo(database);
|
||||
} else {
|
||||
server = registerBungeeInfo(database);
|
||||
}
|
||||
} catch (DBOpException e) {
|
||||
} catch (DBOpException | ExecutionException e) {
|
||||
throw new EnableException("Failed to read Server information from Database.");
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
return server;
|
||||
}
|
||||
@ -78,7 +83,7 @@ public class BungeeServerInfo extends ServerInfo {
|
||||
String accessAddress = webServer.get().getAccessAddress();
|
||||
if (!accessAddress.equals(server.getWebAddress())) {
|
||||
server.setWebAddress(accessAddress);
|
||||
db.save().serverInfoForThisServer(server);
|
||||
db.executeTransaction(new StoreServerInformationTransaction(server));
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,26 +96,18 @@ public class BungeeServerInfo extends ServerInfo {
|
||||
}
|
||||
}
|
||||
|
||||
private Server registerBungeeInfo(Database db) throws EnableException {
|
||||
private Server registerBungeeInfo(Database db) throws EnableException, ExecutionException, InterruptedException {
|
||||
UUID serverUUID = generateNewUUID();
|
||||
String accessAddress = webServer.get().getAccessAddress();
|
||||
|
||||
Server bungeeCord = new Server(-1, serverUUID, "BungeeCord", accessAddress, serverProperties.getMaxPlayers());
|
||||
db.save().serverInfoForThisServer(bungeeCord);
|
||||
Server proxy = new Server(-1, serverUUID, "BungeeCord", accessAddress, serverProperties.getMaxPlayers());
|
||||
db.executeTransaction(new StoreServerInformationTransaction(proxy))
|
||||
.get();
|
||||
|
||||
Optional<Server> bungeeInfo = db.fetch().getBungeeInformation();
|
||||
if (bungeeInfo.isPresent()) {
|
||||
return bungeeInfo.get();
|
||||
Optional<Server> proxyInfo = db.query(ServerQueries.fetchProxyServerInformation());
|
||||
if (proxyInfo.isPresent()) {
|
||||
return proxyInfo.get();
|
||||
}
|
||||
throw new EnableException("BungeeCord registration failed (DB)");
|
||||
}
|
||||
|
||||
private UUID generateNewUUID() {
|
||||
String seed = serverProperties.getName() +
|
||||
serverProperties.getIp() +
|
||||
serverProperties.getPort() +
|
||||
serverProperties.getVersion() +
|
||||
serverProperties.getImplVersion();
|
||||
return UUID.nameUUIDFromBytes(seed.getBytes());
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,12 @@
|
||||
package com.djrapitops.plan.system.listeners.bungee;
|
||||
|
||||
import com.djrapitops.plan.data.container.Session;
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.db.access.transactions.events.GeoInfoStoreTransaction;
|
||||
import com.djrapitops.plan.db.access.transactions.events.PlayerRegisterTransaction;
|
||||
import com.djrapitops.plan.system.cache.GeolocationCache;
|
||||
import com.djrapitops.plan.system.cache.SessionCache;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.info.server.ServerInfo;
|
||||
import com.djrapitops.plan.system.processing.Processing;
|
||||
import com.djrapitops.plan.system.processing.processors.Processors;
|
||||
@ -48,6 +53,8 @@ public class PlayerOnlineListener implements Listener {
|
||||
private final PlanConfig config;
|
||||
private final Processors processors;
|
||||
private final Processing processing;
|
||||
private final DBSystem dbSystem;
|
||||
private final GeolocationCache geolocationCache;
|
||||
private final SessionCache sessionCache;
|
||||
private final ServerInfo serverInfo;
|
||||
private final ErrorHandler errorHandler;
|
||||
@ -57,6 +64,8 @@ public class PlayerOnlineListener implements Listener {
|
||||
PlanConfig config,
|
||||
Processors processors,
|
||||
Processing processing,
|
||||
DBSystem dbSystem,
|
||||
GeolocationCache geolocationCache,
|
||||
SessionCache sessionCache,
|
||||
ServerInfo serverInfo,
|
||||
ErrorHandler errorHandler
|
||||
@ -64,6 +73,8 @@ public class PlayerOnlineListener implements Listener {
|
||||
this.config = config;
|
||||
this.processors = processors;
|
||||
this.processing = processing;
|
||||
this.dbSystem = dbSystem;
|
||||
this.geolocationCache = geolocationCache;
|
||||
this.sessionCache = sessionCache;
|
||||
this.serverInfo = serverInfo;
|
||||
this.errorHandler = errorHandler;
|
||||
@ -73,19 +84,23 @@ public class PlayerOnlineListener implements Listener {
|
||||
public void onPostLogin(PostLoginEvent event) {
|
||||
try {
|
||||
ProxiedPlayer player = event.getPlayer();
|
||||
UUID uuid = player.getUniqueId();
|
||||
UUID playerUUID = player.getUniqueId();
|
||||
String name = player.getName();
|
||||
InetAddress address = player.getAddress().getAddress();
|
||||
long time = System.currentTimeMillis();
|
||||
|
||||
sessionCache.cacheSession(uuid, new Session(uuid, serverInfo.getServerUUID(), time, null, null));
|
||||
sessionCache.cacheSession(playerUUID, new Session(playerUUID, serverInfo.getServerUUID(), time, null, null));
|
||||
Database database = dbSystem.getDatabase();
|
||||
|
||||
boolean gatheringGeolocations = config.isTrue(DataGatheringSettings.GEOLOCATIONS);
|
||||
if (gatheringGeolocations) {
|
||||
database.executeTransaction(
|
||||
new GeoInfoStoreTransaction(playerUUID, address, time, geolocationCache::getCountry)
|
||||
);
|
||||
}
|
||||
|
||||
processing.submit(processors.player().proxyRegisterProcessor(uuid, name, time,
|
||||
gatheringGeolocations ? processors.player().ipUpdateProcessor(uuid, address, time) : null
|
||||
));
|
||||
processing.submit(processors.info().playerPageUpdateProcessor(uuid));
|
||||
database.executeTransaction(new PlayerRegisterTransaction(playerUUID, () -> time, name));
|
||||
processing.submit(processors.info().playerPageUpdateProcessor(playerUUID));
|
||||
ResponseCache.clearResponse(PageId.SERVER.of(serverInfo.getServerUUID()));
|
||||
} catch (Exception e) {
|
||||
errorHandler.log(L.WARN, this.getClass(), e);
|
||||
@ -96,10 +111,10 @@ public class PlayerOnlineListener implements Listener {
|
||||
public void onLogout(PlayerDisconnectEvent event) {
|
||||
try {
|
||||
ProxiedPlayer player = event.getPlayer();
|
||||
UUID uuid = player.getUniqueId();
|
||||
UUID playerUUID = player.getUniqueId();
|
||||
|
||||
sessionCache.endSession(uuid, System.currentTimeMillis());
|
||||
processing.submit(processors.info().playerPageUpdateProcessor(uuid));
|
||||
sessionCache.endSession(playerUUID, System.currentTimeMillis());
|
||||
processing.submit(processors.info().playerPageUpdateProcessor(playerUUID));
|
||||
ResponseCache.clearResponse(PageId.SERVER.of(serverInfo.getServerUUID()));
|
||||
} catch (Exception e) {
|
||||
errorHandler.log(L.WARN, this.getClass(), e);
|
||||
@ -110,12 +125,12 @@ public class PlayerOnlineListener implements Listener {
|
||||
public void onServerSwitch(ServerSwitchEvent event) {
|
||||
try {
|
||||
ProxiedPlayer player = event.getPlayer();
|
||||
UUID uuid = player.getUniqueId();
|
||||
UUID playerUUID = player.getUniqueId();
|
||||
|
||||
long time = System.currentTimeMillis();
|
||||
// Replaces the current session in the cache.
|
||||
sessionCache.cacheSession(uuid, new Session(uuid, serverInfo.getServerUUID(), time, null, null));
|
||||
processing.submit(processors.info().playerPageUpdateProcessor(uuid));
|
||||
sessionCache.cacheSession(playerUUID, new Session(playerUUID, serverInfo.getServerUUID(), time, null, null));
|
||||
processing.submit(processors.info().playerPageUpdateProcessor(playerUUID));
|
||||
} catch (Exception e) {
|
||||
errorHandler.log(L.WARN, this.getClass(), e);
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
package com.djrapitops.plan.system.tasks;
|
||||
|
||||
import com.djrapitops.plan.PlanBungee;
|
||||
import com.djrapitops.plan.db.tasks.DBCleanTask;
|
||||
import com.djrapitops.plan.system.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.system.settings.paths.TimeSettings;
|
||||
import com.djrapitops.plan.system.tasks.bungee.BungeeTPSCountTimer;
|
||||
@ -27,6 +28,7 @@ import com.djrapitops.plugin.api.TimeAmount;
|
||||
import com.djrapitops.plugin.task.RunnableFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
@ -34,6 +36,7 @@ import java.util.concurrent.TimeUnit;
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Singleton
|
||||
public class BungeeTaskSystem extends TaskSystem {
|
||||
|
||||
private final PlanBungee plugin;
|
||||
@ -43,6 +46,7 @@ public class BungeeTaskSystem extends TaskSystem {
|
||||
private final LogsFolderCleanTask logsFolderCleanTask;
|
||||
private final PlayersPageRefreshTask playersPageRefreshTask;
|
||||
private final NetworkConfigStoreTask networkConfigStoreTask;
|
||||
private final DBCleanTask dbCleanTask;
|
||||
|
||||
@Inject
|
||||
public BungeeTaskSystem(
|
||||
@ -54,7 +58,8 @@ public class BungeeTaskSystem extends TaskSystem {
|
||||
PingCountTimerBungee pingCountTimer,
|
||||
LogsFolderCleanTask logsFolderCleanTask,
|
||||
PlayersPageRefreshTask playersPageRefreshTask,
|
||||
NetworkConfigStoreTask networkConfigStoreTask
|
||||
NetworkConfigStoreTask networkConfigStoreTask,
|
||||
DBCleanTask dbCleanTask
|
||||
) {
|
||||
super(runnableFactory, bungeeTPSCountTimer);
|
||||
this.plugin = plugin;
|
||||
@ -65,6 +70,7 @@ public class BungeeTaskSystem extends TaskSystem {
|
||||
this.logsFolderCleanTask = logsFolderCleanTask;
|
||||
this.playersPageRefreshTask = playersPageRefreshTask;
|
||||
this.networkConfigStoreTask = networkConfigStoreTask;
|
||||
this.dbCleanTask = dbCleanTask;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -87,5 +93,10 @@ public class BungeeTaskSystem extends TaskSystem {
|
||||
// +40 ticks / 2 seconds so that update check task runs first.
|
||||
long storeDelay = TimeAmount.toTicks(config.get(TimeSettings.CONFIG_UPDATE_INTERVAL), TimeUnit.MILLISECONDS) + 40;
|
||||
registerTask("Config Store Task", networkConfigStoreTask).runTaskLaterAsynchronously(storeDelay);
|
||||
|
||||
registerTask("DB Clean Task", dbCleanTask).runTaskTimerAsynchronously(
|
||||
TimeAmount.toTicks(20, TimeUnit.SECONDS),
|
||||
TimeAmount.toTicks(config.get(TimeSettings.CLEAN_DATABASE_PERIOD), TimeUnit.MILLISECONDS)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -18,9 +18,9 @@ package com.djrapitops.plan.system.tasks.bungee;
|
||||
|
||||
import com.djrapitops.plan.data.container.TPS;
|
||||
import com.djrapitops.plan.data.container.builders.TPSBuilder;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.info.server.ServerInfo;
|
||||
import com.djrapitops.plan.system.info.server.properties.ServerProperties;
|
||||
import com.djrapitops.plan.system.processing.Processing;
|
||||
import com.djrapitops.plan.system.processing.processors.Processors;
|
||||
import com.djrapitops.plan.system.tasks.TPSCountTimer;
|
||||
import com.djrapitops.plugin.logging.console.PluginLogger;
|
||||
import com.djrapitops.plugin.logging.error.ErrorHandler;
|
||||
@ -35,13 +35,13 @@ public class BungeeTPSCountTimer extends TPSCountTimer {
|
||||
|
||||
@Inject
|
||||
public BungeeTPSCountTimer(
|
||||
Processors processors,
|
||||
Processing processing,
|
||||
DBSystem dbSystem,
|
||||
ServerInfo serverInfo,
|
||||
ServerProperties serverProperties,
|
||||
PluginLogger logger,
|
||||
ErrorHandler errorHandler
|
||||
) {
|
||||
super(processors, processing, logger, errorHandler);
|
||||
super(dbSystem, serverInfo, logger, errorHandler);
|
||||
this.serverProperties = serverProperties;
|
||||
}
|
||||
|
||||
|
@ -24,8 +24,9 @@
|
||||
package com.djrapitops.plan.system.tasks.bungee;
|
||||
|
||||
import com.djrapitops.plan.data.store.objects.DateObj;
|
||||
import com.djrapitops.plan.system.processing.Processing;
|
||||
import com.djrapitops.plan.system.processing.processors.Processors;
|
||||
import com.djrapitops.plan.db.access.transactions.events.PingStoreTransaction;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.info.server.ServerInfo;
|
||||
import com.djrapitops.plan.system.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.system.settings.paths.TimeSettings;
|
||||
import com.djrapitops.plugin.api.TimeAmount;
|
||||
@ -58,20 +59,20 @@ public class PingCountTimerBungee extends AbsRunnable implements Listener {
|
||||
private final Map<UUID, List<DateObj<Integer>>> playerHistory;
|
||||
|
||||
private final PlanConfig config;
|
||||
private final Processors processors;
|
||||
private final Processing processing;
|
||||
private final DBSystem dbSystem;
|
||||
private final ServerInfo serverInfo;
|
||||
private final RunnableFactory runnableFactory;
|
||||
|
||||
@Inject
|
||||
public PingCountTimerBungee(
|
||||
PlanConfig config,
|
||||
Processors processors,
|
||||
Processing processing,
|
||||
DBSystem dbSystem,
|
||||
ServerInfo serverInfo,
|
||||
RunnableFactory runnableFactory
|
||||
) {
|
||||
this.config = config;
|
||||
this.processors = processors;
|
||||
this.processing = processing;
|
||||
this.dbSystem = dbSystem;
|
||||
this.serverInfo = serverInfo;
|
||||
this.runnableFactory = runnableFactory;
|
||||
playerHistory = new HashMap<>();
|
||||
}
|
||||
@ -94,7 +95,9 @@ public class PingCountTimerBungee extends AbsRunnable implements Listener {
|
||||
}
|
||||
history.add(new DateObj<>(time, ping));
|
||||
if (history.size() >= 30) {
|
||||
processing.submit(processors.player().pingInsertProcessor(uuid, new ArrayList<>(history)));
|
||||
dbSystem.getDatabase().executeTransaction(
|
||||
new PingStoreTransaction(uuid, serverInfo.getServerUUID(), new ArrayList<>(history))
|
||||
);
|
||||
history.clear();
|
||||
}
|
||||
} else {
|
||||
|
@ -17,11 +17,13 @@
|
||||
package com.djrapitops.plan;
|
||||
|
||||
import com.djrapitops.plan.api.exceptions.EnableException;
|
||||
import com.djrapitops.plan.db.SQLiteDB;
|
||||
import com.djrapitops.plan.system.PlanSystem;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.system.settings.paths.ProxySettings;
|
||||
import com.djrapitops.plan.system.settings.paths.WebserverSettings;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
@ -62,7 +64,9 @@ public class BungeeSystemTest {
|
||||
config.set(ProxySettings.IP, "8.8.8.8");
|
||||
|
||||
DBSystem dbSystem = bungeeSystem.getDatabaseSystem();
|
||||
dbSystem.setActiveDatabase(dbSystem.getSqLiteFactory().usingDefaultFile());
|
||||
SQLiteDB db = dbSystem.getSqLiteFactory().usingDefaultFile();
|
||||
db.setTransactionExecutorServiceProvider(MoreExecutors::newDirectExecutorService);
|
||||
dbSystem.setActiveDatabase(db);
|
||||
|
||||
bungeeSystem.enable();
|
||||
} finally {
|
||||
@ -82,7 +86,9 @@ public class BungeeSystemTest {
|
||||
config.set(ProxySettings.IP, "0.0.0.0");
|
||||
|
||||
DBSystem dbSystem = bungeeSystem.getDatabaseSystem();
|
||||
dbSystem.setActiveDatabase(dbSystem.getSqLiteFactory().usingDefaultFile());
|
||||
SQLiteDB db = dbSystem.getSqLiteFactory().usingDefaultFile();
|
||||
db.setTransactionExecutorServiceProvider(MoreExecutors::newDirectExecutorService);
|
||||
dbSystem.setActiveDatabase(db);
|
||||
|
||||
bungeeSystem.enable();
|
||||
assertTrue(bungeeSystem.isEnabled());
|
||||
|
@ -0,0 +1,135 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import com.djrapitops.plan.api.exceptions.database.DBInitException;
|
||||
import com.djrapitops.plan.api.exceptions.database.DBOpException;
|
||||
import com.djrapitops.plan.data.container.Session;
|
||||
import com.djrapitops.plan.data.store.keys.SessionKeys;
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.db.access.transactions.events.ServerShutdownTransaction;
|
||||
import com.djrapitops.plan.system.cache.SessionCache;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.locale.Locale;
|
||||
import com.djrapitops.plan.system.locale.lang.PluginLang;
|
||||
import com.djrapitops.plugin.logging.L;
|
||||
import com.djrapitops.plugin.logging.console.PluginLogger;
|
||||
import com.djrapitops.plugin.logging.error.ErrorHandler;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
/**
|
||||
* Class in charge of performing save operations when the server shuts down.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public abstract class ServerShutdownSave {
|
||||
|
||||
protected final PluginLogger logger;
|
||||
private final DBSystem dbSystem;
|
||||
private final Locale locale;
|
||||
private final ErrorHandler errorHandler;
|
||||
private boolean shuttingDown = false;
|
||||
|
||||
public ServerShutdownSave(
|
||||
Locale locale,
|
||||
DBSystem dbSystem,
|
||||
PluginLogger logger,
|
||||
ErrorHandler errorHandler
|
||||
) {
|
||||
this.locale = locale;
|
||||
this.dbSystem = dbSystem;
|
||||
this.logger = logger;
|
||||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
protected abstract boolean checkServerShuttingDownStatus();
|
||||
|
||||
public void serverIsKnownToBeShuttingDown() {
|
||||
shuttingDown = true;
|
||||
}
|
||||
|
||||
public void performSave() {
|
||||
if (!checkServerShuttingDownStatus() && !shuttingDown) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<UUID, Session> activeSessions = SessionCache.getActiveSessions();
|
||||
if (activeSessions.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This check ensures that logging is not attempted on JVM shutdown.
|
||||
// Underlying Logger might not be available leading to an exception.
|
||||
if (!shuttingDown) {
|
||||
logger.info(locale.getString(PluginLang.DISABLED_UNSAVED_SESSIONS));
|
||||
}
|
||||
attemptSave(activeSessions);
|
||||
|
||||
SessionCache.clear();
|
||||
}
|
||||
|
||||
private void attemptSave(Map<UUID, Session> activeSessions) {
|
||||
try {
|
||||
prepareSessionsForStorage(activeSessions, System.currentTimeMillis());
|
||||
saveActiveSessions(activeSessions);
|
||||
} catch (DBInitException e) {
|
||||
errorHandler.log(L.ERROR, this.getClass(), e);
|
||||
} catch (IllegalStateException ignored) {
|
||||
/* Database is not initialized */
|
||||
} finally {
|
||||
closeDatabase(dbSystem.getDatabase());
|
||||
}
|
||||
}
|
||||
|
||||
private void saveActiveSessions(Map<UUID, Session> activeSessions) {
|
||||
Database database = dbSystem.getDatabase();
|
||||
if (database.getState() == Database.State.CLOSED) {
|
||||
// Ensure that database is not closed when performing the transaction.
|
||||
database.init();
|
||||
}
|
||||
|
||||
saveSessions(activeSessions, database);
|
||||
}
|
||||
|
||||
private void prepareSessionsForStorage(Map<UUID, Session> activeSessions, long now) {
|
||||
for (Session session : activeSessions.values()) {
|
||||
Optional<Long> end = session.getValue(SessionKeys.END);
|
||||
if (!end.isPresent()) {
|
||||
session.endSession(now);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void saveSessions(Map<UUID, Session> activeSessions, Database database) {
|
||||
try {
|
||||
database.executeTransaction(new ServerShutdownTransaction(activeSessions.values()))
|
||||
.get(); // Ensure that the transaction is executed before shutdown.
|
||||
} catch (ExecutionException | DBOpException e) {
|
||||
errorHandler.log(L.ERROR, this.getClass(), e);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
private void closeDatabase(Database database) {
|
||||
database.close();
|
||||
}
|
||||
}
|
@ -16,21 +16,8 @@
|
||||
*/
|
||||
package com.djrapitops.plan;
|
||||
|
||||
import com.djrapitops.plan.api.exceptions.database.DBException;
|
||||
import com.djrapitops.plan.api.exceptions.database.DBInitException;
|
||||
import com.djrapitops.plan.api.exceptions.database.DBOpException;
|
||||
import com.djrapitops.plan.data.container.Session;
|
||||
import com.djrapitops.plan.data.store.keys.SessionKeys;
|
||||
import com.djrapitops.plan.system.cache.SessionCache;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.database.databases.Database;
|
||||
import com.djrapitops.plugin.logging.L;
|
||||
import com.djrapitops.plugin.logging.error.ErrorHandler;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
/**
|
||||
* Thread that is run when JVM shuts down.
|
||||
@ -39,16 +26,16 @@ import java.util.UUID;
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Singleton
|
||||
public class ShutdownHook extends Thread {
|
||||
|
||||
private static ShutdownHook activated;
|
||||
private final DBSystem dbSystem;
|
||||
private final ErrorHandler errorHandler;
|
||||
|
||||
private final ServerShutdownSave serverShutdownSave;
|
||||
|
||||
@Inject
|
||||
public ShutdownHook(DBSystem dbSystem, ErrorHandler errorHandler) {
|
||||
this.dbSystem = dbSystem;
|
||||
this.errorHandler = errorHandler;
|
||||
public ShutdownHook(ServerShutdownSave serverShutdownSave) {
|
||||
this.serverShutdownSave = serverShutdownSave;
|
||||
}
|
||||
|
||||
private static boolean isActivated() {
|
||||
@ -74,41 +61,7 @@ public class ShutdownHook extends Thread {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Map<UUID, Session> activeSessions = SessionCache.getActiveSessions();
|
||||
long now = System.currentTimeMillis();
|
||||
saveActiveSessions(activeSessions, now);
|
||||
} catch (IllegalStateException ignored) {
|
||||
/* Database is not initialized */
|
||||
} catch (DBInitException e) {
|
||||
errorHandler.log(L.ERROR, this.getClass(), e);
|
||||
} finally {
|
||||
try {
|
||||
dbSystem.getDatabase().close();
|
||||
} catch (DBException e) {
|
||||
errorHandler.log(L.ERROR, this.getClass(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void saveActiveSessions(Map<UUID, Session> activeSessions, long now) throws DBInitException {
|
||||
for (Map.Entry<UUID, Session> entry : activeSessions.entrySet()) {
|
||||
UUID uuid = entry.getKey();
|
||||
Session session = entry.getValue();
|
||||
Optional<Long> end = session.getValue(SessionKeys.END);
|
||||
if (!end.isPresent()) {
|
||||
session.endSession(now);
|
||||
}
|
||||
Database database = dbSystem.getDatabase();
|
||||
if (!database.isOpen()) {
|
||||
database.init();
|
||||
}
|
||||
try {
|
||||
database.save().session(uuid, session);
|
||||
} catch (DBOpException e) {
|
||||
errorHandler.log(L.ERROR, this.getClass(), e);
|
||||
}
|
||||
}
|
||||
activeSessions.clear();
|
||||
serverShutdownSave.serverIsKnownToBeShuttingDown();
|
||||
serverShutdownSave.performSave();
|
||||
}
|
||||
}
|
||||
|
@ -16,11 +16,26 @@
|
||||
*/
|
||||
package com.djrapitops.plan.api;
|
||||
|
||||
import com.djrapitops.plan.api.data.PlayerContainer;
|
||||
import com.djrapitops.plan.api.data.ServerContainer;
|
||||
import com.djrapitops.plan.api.exceptions.database.DBOpException;
|
||||
import com.djrapitops.plan.data.plugin.HookHandler;
|
||||
import com.djrapitops.plan.data.plugin.PluginData;
|
||||
import com.djrapitops.plan.db.access.Query;
|
||||
import com.djrapitops.plan.db.access.queries.containers.ContainerFetchQueries;
|
||||
import com.djrapitops.plan.db.access.queries.objects.ServerQueries;
|
||||
import com.djrapitops.plan.db.access.queries.objects.UserIdentifierQueries;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.database.databases.operation.FetchOperations;
|
||||
import com.djrapitops.plan.system.database.databases.sql.operation.SQLFetchOps;
|
||||
import com.djrapitops.plan.utilities.uuid.UUIDUtility;
|
||||
import com.djrapitops.plugin.logging.L;
|
||||
import com.djrapitops.plugin.logging.console.PluginLogger;
|
||||
import com.djrapitops.plugin.logging.error.ErrorHandler;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
@ -30,17 +45,36 @@ import java.util.UUID;
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public abstract class CommonAPI implements PlanAPI {
|
||||
@Singleton
|
||||
public class CommonAPI implements PlanAPI {
|
||||
|
||||
private final DBSystem dbSystem;
|
||||
private final UUIDUtility uuidUtility;
|
||||
private final HookHandler hookHandler;
|
||||
private final PluginLogger logger;
|
||||
private final ErrorHandler errorHandler;
|
||||
|
||||
CommonAPI(UUIDUtility uuidUtility, ErrorHandler errorHandler) {
|
||||
@Inject
|
||||
public CommonAPI(
|
||||
DBSystem dbSystem,
|
||||
UUIDUtility uuidUtility,
|
||||
HookHandler hookHandler,
|
||||
PluginLogger logger,
|
||||
ErrorHandler errorHandler
|
||||
) {
|
||||
this.dbSystem = dbSystem;
|
||||
this.uuidUtility = uuidUtility;
|
||||
this.hookHandler = hookHandler;
|
||||
this.logger = logger;
|
||||
this.errorHandler = errorHandler;
|
||||
PlanAPIHolder.set(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPluginDataSource(PluginData pluginData) {
|
||||
hookHandler.addPluginDataSource(pluginData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPlayerInspectPageLink(UUID uuid) {
|
||||
return getPlayerInspectPageLink(getPlayerName(uuid));
|
||||
@ -59,11 +93,43 @@ public abstract class CommonAPI implements PlanAPI {
|
||||
@Override
|
||||
public Map<UUID, String> getKnownPlayerNames() {
|
||||
try {
|
||||
return fetchFromPlanDB().getPlayerNames();
|
||||
return queryDB(UserIdentifierQueries.fetchAllPlayerNames());
|
||||
} catch (DBOpException e) {
|
||||
errorHandler.log(L.ERROR, this.getClass(), e);
|
||||
return new HashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlayerContainer fetchPlayerContainer(UUID uuid) {
|
||||
return new PlayerContainer(queryDB(ContainerFetchQueries.fetchPlayerContainer(uuid)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerContainer fetchServerContainer(UUID serverUUID) {
|
||||
return new ServerContainer(queryDB(ContainerFetchQueries.fetchServerContainer(serverUUID)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<UUID> fetchServerUUIDs() {
|
||||
return queryDB(ServerQueries.fetchPlanServerInformation()).keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPlayerName(UUID playerUUID) {
|
||||
return queryDB(UserIdentifierQueries.fetchPlayerNameOf(playerUUID)).orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FetchOperations fetchFromPlanDB() {
|
||||
logger.warn("PlanAPI#fetchFromPlanDB has been deprecated and will be removed in the future. Stack trace to follow");
|
||||
for (StackTraceElement element : Thread.currentThread().getStackTrace()) {
|
||||
logger.warn(element.toString());
|
||||
}
|
||||
return new SQLFetchOps(dbSystem.getDatabase());
|
||||
}
|
||||
|
||||
private <T> T queryDB(Query<T> query) {
|
||||
return dbSystem.getDatabase().query(query);
|
||||
}
|
||||
}
|
||||
|
@ -79,9 +79,7 @@ public interface PlanAPI {
|
||||
* @param uuid UUID of the player.
|
||||
* @return a {@link PlayerContainer}.
|
||||
*/
|
||||
default PlayerContainer fetchPlayerContainer(UUID uuid) {
|
||||
return new PlayerContainer(fetchFromPlanDB().getPlayerContainer(uuid));
|
||||
}
|
||||
PlayerContainer fetchPlayerContainer(UUID uuid);
|
||||
|
||||
/**
|
||||
* Fetch a ServerContainer from the database.
|
||||
@ -91,16 +89,12 @@ public interface PlanAPI {
|
||||
* @param serverUUID UUID of the server.
|
||||
* @return a {@link ServerContainer}.
|
||||
*/
|
||||
default ServerContainer fetchServerContainer(UUID serverUUID) {
|
||||
return new ServerContainer(fetchFromPlanDB().getServerContainer(serverUUID));
|
||||
}
|
||||
ServerContainer fetchServerContainer(UUID serverUUID);
|
||||
|
||||
/**
|
||||
* Fetch server UUIDs.
|
||||
*
|
||||
* @return All Plan server UUIDs.
|
||||
*/
|
||||
default Collection<UUID> fetchServerUUIDs() {
|
||||
return fetchFromPlanDB().getServerUUIDs();
|
||||
}
|
||||
Collection<UUID> fetchServerUUIDs();
|
||||
}
|
||||
|
@ -1,68 +0,0 @@
|
||||
/*
|
||||
* 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.api;
|
||||
|
||||
import com.djrapitops.plan.data.plugin.HookHandler;
|
||||
import com.djrapitops.plan.data.plugin.PluginData;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.database.databases.operation.FetchOperations;
|
||||
import com.djrapitops.plan.utilities.uuid.UUIDUtility;
|
||||
import com.djrapitops.plugin.logging.error.ErrorHandler;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* PlanAPI extension for proxy servers.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Singleton
|
||||
public class ProxyAPI extends CommonAPI {
|
||||
|
||||
private final HookHandler hookHandler;
|
||||
private final DBSystem dbSystem;
|
||||
|
||||
@Inject
|
||||
public ProxyAPI(
|
||||
UUIDUtility uuidUtility,
|
||||
DBSystem dbSystem,
|
||||
HookHandler hookHandler,
|
||||
ErrorHandler errorHandler
|
||||
) {
|
||||
super(uuidUtility, errorHandler);
|
||||
|
||||
this.dbSystem = dbSystem;
|
||||
this.hookHandler = hookHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPluginDataSource(PluginData pluginData) {
|
||||
hookHandler.addPluginDataSource(pluginData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPlayerName(UUID uuid) {
|
||||
return dbSystem.getDatabase().fetch().getPlayerName(uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FetchOperations fetchFromPlanDB() {
|
||||
return dbSystem.getDatabase().fetch();
|
||||
}
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
/*
|
||||
* 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.api;
|
||||
|
||||
import com.djrapitops.plan.data.plugin.HookHandler;
|
||||
import com.djrapitops.plan.data.plugin.PluginData;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.database.databases.operation.FetchOperations;
|
||||
import com.djrapitops.plan.utilities.uuid.UUIDUtility;
|
||||
import com.djrapitops.plugin.logging.error.ErrorHandler;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* PlanAPI extension for Bukkit
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Singleton
|
||||
public class ServerAPI extends CommonAPI {
|
||||
|
||||
private final HookHandler hookHandler;
|
||||
private final DBSystem dbSystem;
|
||||
|
||||
@Inject
|
||||
public ServerAPI(
|
||||
UUIDUtility uuidUtility,
|
||||
HookHandler hookHandler,
|
||||
DBSystem dbSystem,
|
||||
ErrorHandler errorHandler
|
||||
) {
|
||||
super(uuidUtility, errorHandler);
|
||||
this.hookHandler = hookHandler;
|
||||
this.dbSystem = dbSystem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPluginDataSource(PluginData pluginData) {
|
||||
hookHandler.addPluginDataSource(pluginData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPlayerName(UUID uuid) {
|
||||
return dbSystem.getDatabase().fetch().getPlayerName(uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FetchOperations fetchFromPlanDB() {
|
||||
return dbSystem.getDatabase().fetch();
|
||||
}
|
||||
}
|
@ -17,7 +17,7 @@
|
||||
package com.djrapitops.plan.api.exceptions.connection;
|
||||
|
||||
/**
|
||||
* Thrown when DBException occurs during InfoRequest#placeIntoDatabase.
|
||||
* Thrown when {@link com.djrapitops.plan.api.exceptions.database.DBOpException} occurs during {@link com.djrapitops.plan.system.info.request.InfoRequest#placeIntoDatabase}.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
|
@ -1,37 +0,0 @@
|
||||
/*
|
||||
* 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.api.exceptions.database;
|
||||
|
||||
/**
|
||||
* Thrown when something goes wrong with the Database, generic exception.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class DBException extends Exception {
|
||||
|
||||
public DBException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public DBException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public DBException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
@ -21,16 +21,12 @@ package com.djrapitops.plan.api.exceptions.database;
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class DBInitException extends FatalDBException {
|
||||
public class DBInitException extends DBOpException {
|
||||
|
||||
public DBInitException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public DBInitException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public DBInitException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ import java.sql.SQLException;
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class DBOpException extends RuntimeException {
|
||||
public class DBOpException extends IllegalStateException {
|
||||
|
||||
public DBOpException(String message) {
|
||||
super(message);
|
||||
|
@ -16,15 +16,7 @@
|
||||
*/
|
||||
package com.djrapitops.plan.api.exceptions.database;
|
||||
|
||||
public class FatalDBException extends DBException {
|
||||
|
||||
public FatalDBException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public FatalDBException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
public class FatalDBException extends DBOpException {
|
||||
|
||||
public FatalDBException(String message) {
|
||||
super(message);
|
||||
|
@ -18,6 +18,9 @@ package com.djrapitops.plan.command.commands;
|
||||
|
||||
import com.djrapitops.plan.api.exceptions.connection.WebException;
|
||||
import com.djrapitops.plan.api.exceptions.database.DBOpException;
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.db.access.queries.objects.ServerQueries;
|
||||
import com.djrapitops.plan.db.access.queries.objects.WebUserQueries;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.info.InfoSystem;
|
||||
import com.djrapitops.plan.system.info.connection.ConnectionSystem;
|
||||
@ -40,7 +43,6 @@ import com.djrapitops.plugin.logging.error.ErrorHandler;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
@ -89,6 +91,12 @@ public class AnalyzeCommand extends CommandNode {
|
||||
|
||||
@Override
|
||||
public void onCommand(Sender sender, String commandLabel, String[] args) {
|
||||
Database.State dbState = dbSystem.getDatabase().getState();
|
||||
if (dbState != Database.State.OPEN) {
|
||||
sender.sendMessage(locale.getString(CommandLang.FAIL_DATABASE_NOT_OPEN, dbState.name()));
|
||||
return;
|
||||
}
|
||||
|
||||
sender.sendMessage(locale.getString(ManageLang.PROGRESS_START));
|
||||
|
||||
processing.submitNonCritical(() -> {
|
||||
@ -125,23 +133,16 @@ public class AnalyzeCommand extends CommandNode {
|
||||
private void sendWebUserNotificationIfNecessary(Sender sender) {
|
||||
if (webServer.isAuthRequired() &&
|
||||
CommandUtils.isPlayer(sender) &&
|
||||
!dbSystem.getDatabase().check().doesWebUserExists(sender.getName())) {
|
||||
!dbSystem.getDatabase().query(WebUserQueries.fetchWebUser(sender.getName())).isPresent()) {
|
||||
sender.sendMessage("§e" + locale.getString(CommandLang.NO_WEB_USER_NOTIFY));
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<Server> getServer(String[] args) {
|
||||
if (args.length >= 1 && connectionSystem.isServerAvailable()) {
|
||||
Map<UUID, Server> bukkitServers = dbSystem.getDatabase().fetch().getBukkitServers();
|
||||
String serverIdentifier = getGivenIdentifier(args);
|
||||
for (Map.Entry<UUID, Server> entry : bukkitServers.entrySet()) {
|
||||
Server server = entry.getValue();
|
||||
|
||||
if (Integer.toString(server.getId()).equals(serverIdentifier)
|
||||
|| server.getName().equalsIgnoreCase(serverIdentifier)) {
|
||||
return Optional.of(server);
|
||||
}
|
||||
}
|
||||
return dbSystem.getDatabase().query(ServerQueries.fetchServerMatchingIdentifier(serverIdentifier))
|
||||
.filter(server -> !server.isProxy());
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
package com.djrapitops.plan.command.commands;
|
||||
|
||||
import com.djrapitops.plan.PlanPlugin;
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.info.connection.ConnectionSystem;
|
||||
import com.djrapitops.plan.system.locale.Locale;
|
||||
@ -70,12 +71,15 @@ public class InfoCommand extends CommandNode {
|
||||
|
||||
String updateAvailable = versionCheckSystem.isNewVersionAvailable() ? yes : no;
|
||||
String connectedToBungee = connectionSystem.isServerAvailable() ? yes : no;
|
||||
|
||||
Database database = dbSystem.getDatabase();
|
||||
|
||||
String[] messages = {
|
||||
locale.getString(CommandLang.HEADER_INFO),
|
||||
"",
|
||||
locale.getString(CommandLang.INFO_VERSION, plugin.getVersion()),
|
||||
locale.getString(CommandLang.INFO_UPDATE, updateAvailable),
|
||||
locale.getString(CommandLang.INFO_DATABASE, dbSystem.getDatabase().getType().getName()),
|
||||
locale.getString(CommandLang.INFO_DATABASE, database.getType().getName() + " (" + database.getState().name() + ")"),
|
||||
locale.getString(CommandLang.INFO_BUNGEE_CONNECTION, connectedToBungee),
|
||||
"",
|
||||
">"
|
||||
|
@ -17,6 +17,9 @@
|
||||
package com.djrapitops.plan.command.commands;
|
||||
|
||||
import com.djrapitops.plan.api.exceptions.database.DBOpException;
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.db.access.queries.PlayerFetchQueries;
|
||||
import com.djrapitops.plan.db.access.queries.objects.WebUserQueries;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.info.connection.ConnectionSystem;
|
||||
import com.djrapitops.plan.system.locale.Locale;
|
||||
@ -90,25 +93,31 @@ public class InspectCommand extends CommandNode {
|
||||
sender.sendMessage(locale.getString(CommandLang.FAIL_NO_PERMISSION));
|
||||
}
|
||||
|
||||
Database.State dbState = dbSystem.getDatabase().getState();
|
||||
if (dbState != Database.State.OPEN) {
|
||||
sender.sendMessage(locale.getString(CommandLang.FAIL_DATABASE_NOT_OPEN, dbState.name()));
|
||||
return;
|
||||
}
|
||||
|
||||
runInspectTask(playerName, sender);
|
||||
}
|
||||
|
||||
private void runInspectTask(String playerName, Sender sender) {
|
||||
processing.submitNonCritical(() -> {
|
||||
try {
|
||||
UUID uuid = uuidUtility.getUUIDOf(playerName);
|
||||
if (uuid == null) {
|
||||
UUID playerUUID = uuidUtility.getUUIDOf(playerName);
|
||||
if (playerUUID == null) {
|
||||
sender.sendMessage(locale.getString(CommandLang.FAIL_USERNAME_NOT_VALID));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dbSystem.getDatabase().check().isPlayerRegistered(uuid)) {
|
||||
if (!dbSystem.getDatabase().query(PlayerFetchQueries.isPlayerRegistered(playerUUID))) {
|
||||
sender.sendMessage(locale.getString(CommandLang.FAIL_USERNAME_NOT_KNOWN));
|
||||
return;
|
||||
}
|
||||
|
||||
checkWebUserAndNotify(sender);
|
||||
processing.submit(processorFactory.inspectCacheRequestProcessor(uuid, sender, playerName, this::sendInspectMsg));
|
||||
processing.submit(processorFactory.inspectCacheRequestProcessor(playerUUID, sender, playerName, this::sendInspectMsg));
|
||||
} catch (DBOpException e) {
|
||||
sender.sendMessage("§eDatabase exception occurred: " + e.getMessage());
|
||||
errorHandler.log(L.ERROR, this.getClass(), e);
|
||||
@ -118,7 +127,7 @@ public class InspectCommand extends CommandNode {
|
||||
|
||||
private void checkWebUserAndNotify(Sender sender) {
|
||||
if (CommandUtils.isPlayer(sender) && webServer.isAuthRequired()) {
|
||||
boolean senderHasWebUser = dbSystem.getDatabase().check().doesWebUserExists(sender.getName());
|
||||
boolean senderHasWebUser = dbSystem.getDatabase().query(WebUserQueries.fetchWebUser(sender.getName())).isPresent();
|
||||
|
||||
if (!senderHasWebUser) {
|
||||
sender.sendMessage("§e" + locale.getString(CommandLang.NO_WEB_USER_NOTIFY));
|
||||
|
@ -17,6 +17,8 @@
|
||||
package com.djrapitops.plan.command.commands;
|
||||
|
||||
import com.djrapitops.plan.api.exceptions.database.DBOpException;
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.db.access.queries.objects.ServerQueries;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.info.server.Server;
|
||||
import com.djrapitops.plan.system.locale.Locale;
|
||||
@ -33,6 +35,8 @@ import com.djrapitops.plugin.logging.L;
|
||||
import com.djrapitops.plugin.logging.error.ErrorHandler;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -67,6 +71,12 @@ public class ListServersCommand extends CommandNode {
|
||||
|
||||
@Override
|
||||
public void onCommand(Sender sender, String commandLabel, String[] args) {
|
||||
Database.State dbState = dbSystem.getDatabase().getState();
|
||||
if (dbState != Database.State.OPEN) {
|
||||
sender.sendMessage(locale.getString(CommandLang.FAIL_DATABASE_NOT_OPEN, dbState.name()));
|
||||
return;
|
||||
}
|
||||
|
||||
String sCol = colorScheme.getSecondaryColor();
|
||||
String tCol = colorScheme.getTertiaryColor();
|
||||
Formatter<Server> serverFormatter = serverLister(sCol, tCol);
|
||||
@ -81,7 +91,8 @@ public class ListServersCommand extends CommandNode {
|
||||
}
|
||||
|
||||
private void sendServers(Sender sender, Formatter<Server> serverFormatter) {
|
||||
List<Server> servers = dbSystem.getDatabase().fetch().getServers();
|
||||
List<Server> servers = new ArrayList<>(dbSystem.getDatabase().query(ServerQueries.fetchPlanServerInformation()).values());
|
||||
Collections.sort(servers);
|
||||
for (Server server : servers) {
|
||||
sender.sendMessage(serverFormatter.apply(server));
|
||||
}
|
||||
|
@ -24,6 +24,8 @@ import com.djrapitops.plan.data.store.mutators.ActivityIndex;
|
||||
import com.djrapitops.plan.data.store.mutators.GeoInfoMutator;
|
||||
import com.djrapitops.plan.data.store.mutators.SessionsMutator;
|
||||
import com.djrapitops.plan.data.store.objects.DateHolder;
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.db.access.queries.containers.ContainerFetchQueries;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.locale.Locale;
|
||||
import com.djrapitops.plan.system.locale.lang.CmdHelpLang;
|
||||
@ -101,6 +103,12 @@ public class QInspectCommand extends CommandNode {
|
||||
return;
|
||||
}
|
||||
|
||||
Database.State dbState = dbSystem.getDatabase().getState();
|
||||
if (dbState != Database.State.OPEN) {
|
||||
sender.sendMessage(locale.getString(CommandLang.FAIL_DATABASE_NOT_OPEN, dbState.name()));
|
||||
return;
|
||||
}
|
||||
|
||||
runInspectTask(playerName, sender);
|
||||
}
|
||||
|
||||
@ -113,7 +121,7 @@ public class QInspectCommand extends CommandNode {
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerContainer container = dbSystem.getDatabase().fetch().getPlayerContainer(uuid);
|
||||
PlayerContainer container = dbSystem.getDatabase().query(ContainerFetchQueries.fetchPlayerContainer(uuid));
|
||||
if (!container.getValue(PlayerKeys.REGISTERED).isPresent()) {
|
||||
sender.sendMessage(locale.getString(CommandLang.FAIL_USERNAME_NOT_KNOWN));
|
||||
return;
|
||||
|
@ -17,8 +17,10 @@
|
||||
package com.djrapitops.plan.command.commands;
|
||||
|
||||
import com.djrapitops.plan.data.WebUser;
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.db.access.queries.objects.WebUserQueries;
|
||||
import com.djrapitops.plan.db.access.transactions.commands.RegisterWebUserTransaction;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.database.databases.Database;
|
||||
import com.djrapitops.plan.system.locale.Locale;
|
||||
import com.djrapitops.plan.system.locale.lang.CmdHelpLang;
|
||||
import com.djrapitops.plan.system.locale.lang.CommandLang;
|
||||
@ -86,6 +88,12 @@ public class RegisterCommand extends CommandNode {
|
||||
@Override
|
||||
public void onCommand(Sender sender, String commandLabel, String[] args) {
|
||||
try {
|
||||
Database.State dbState = dbSystem.getDatabase().getState();
|
||||
if (dbState != Database.State.OPEN) {
|
||||
sender.sendMessage(locale.getString(CommandLang.FAIL_DATABASE_NOT_OPEN, dbState.name()));
|
||||
return;
|
||||
}
|
||||
|
||||
if (CommandUtils.isPlayer(sender)) {
|
||||
playerRegister(args, sender);
|
||||
} else {
|
||||
@ -147,12 +155,12 @@ public class RegisterCommand extends CommandNode {
|
||||
String userName = webUser.getName();
|
||||
try {
|
||||
Database database = dbSystem.getDatabase();
|
||||
boolean userExists = database.check().doesWebUserExists(userName);
|
||||
boolean userExists = database.query(WebUserQueries.fetchWebUser(userName)).isPresent();
|
||||
if (userExists) {
|
||||
sender.sendMessage(locale.getString(CommandLang.FAIL_WEB_USER_EXISTS));
|
||||
return;
|
||||
}
|
||||
database.save().webUser(webUser);
|
||||
database.executeTransaction(new RegisterWebUserTransaction(webUser));
|
||||
sender.sendMessage(locale.getString(CommandLang.WEB_USER_REGISTER_SUCCESS, userName));
|
||||
logger.info(locale.getString(CommandLang.WEB_USER_REGISTER_NOTIFY, userName, webUser.getPermLevel()));
|
||||
} catch (Exception e) {
|
||||
|
@ -17,6 +17,8 @@
|
||||
package com.djrapitops.plan.command.commands;
|
||||
|
||||
import com.djrapitops.plan.api.exceptions.database.DBOpException;
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.db.access.queries.objects.UserIdentifierQueries;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.locale.Locale;
|
||||
import com.djrapitops.plan.system.locale.lang.CmdHelpLang;
|
||||
@ -71,6 +73,12 @@ public class SearchCommand extends CommandNode {
|
||||
|
||||
@Override
|
||||
public void onCommand(Sender sender, String commandLabel, String[] args) {
|
||||
Database.State dbState = dbSystem.getDatabase().getState();
|
||||
if (dbState != Database.State.OPEN) {
|
||||
sender.sendMessage(locale.getString(CommandLang.FAIL_DATABASE_NOT_OPEN, dbState.name()));
|
||||
return;
|
||||
}
|
||||
|
||||
Verify.isTrue(args.length >= 1,
|
||||
() -> new IllegalArgumentException(locale.getString(CommandLang.FAIL_REQ_ONE_ARG, Arrays.toString(this.getArguments()))));
|
||||
|
||||
@ -82,12 +90,12 @@ public class SearchCommand extends CommandNode {
|
||||
private void runSearchTask(String[] args, Sender sender) {
|
||||
processing.submitNonCritical(() -> {
|
||||
try {
|
||||
String searchTerm = args[0];
|
||||
List<String> names = dbSystem.getDatabase().search().matchingPlayers(searchTerm);
|
||||
String searchFor = args[0];
|
||||
List<String> names = dbSystem.getDatabase().query(UserIdentifierQueries.fetchMatchingPlayerNames(searchFor));
|
||||
Collections.sort(names);
|
||||
boolean empty = Verify.isEmpty(names);
|
||||
|
||||
sender.sendMessage(locale.getString(CommandLang.HEADER_SEARCH, empty ? 0 : names.size(), searchTerm));
|
||||
sender.sendMessage(locale.getString(CommandLang.HEADER_SEARCH, empty ? 0 : names.size(), searchFor));
|
||||
// Results
|
||||
if (!empty) {
|
||||
String message = names.toString();
|
||||
|
@ -16,12 +16,14 @@
|
||||
*/
|
||||
package com.djrapitops.plan.command.commands.manage;
|
||||
|
||||
import com.djrapitops.plan.api.exceptions.database.DBException;
|
||||
import com.djrapitops.plan.api.exceptions.database.DBInitException;
|
||||
import com.djrapitops.plan.api.exceptions.database.DBOpException;
|
||||
import com.djrapitops.plan.db.DBType;
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.db.SQLiteDB;
|
||||
import com.djrapitops.plan.db.access.queries.ServerAggregateQueries;
|
||||
import com.djrapitops.plan.db.access.transactions.BackupCopyTransaction;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.database.databases.DBType;
|
||||
import com.djrapitops.plan.system.database.databases.Database;
|
||||
import com.djrapitops.plan.system.database.databases.sql.SQLiteDB;
|
||||
import com.djrapitops.plan.system.locale.Locale;
|
||||
import com.djrapitops.plan.system.locale.lang.CmdHelpLang;
|
||||
import com.djrapitops.plan.system.locale.lang.CommandLang;
|
||||
@ -41,8 +43,7 @@ import com.djrapitops.plugin.utilities.Verify;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
/**
|
||||
* This command is used to backup a database to a .db file.
|
||||
@ -109,6 +110,10 @@ public class ManageBackupCommand extends CommandNode {
|
||||
private void runBackupTask(Sender sender, String[] args, Database database) {
|
||||
processing.submitCritical(() -> {
|
||||
try {
|
||||
Database.State dbState = database.getState();
|
||||
if (dbState != Database.State.OPEN) {
|
||||
sender.sendMessage(locale.getString(CommandLang.WARN_DATABASE_NOT_OPEN, dbState.name()));
|
||||
}
|
||||
sender.sendMessage(locale.getString(ManageLang.PROGRESS_START));
|
||||
createNewBackup(args[0], database);
|
||||
sender.sendMessage(locale.getString(ManageLang.PROGRESS_SUCCESS));
|
||||
@ -126,19 +131,22 @@ public class ManageBackupCommand extends CommandNode {
|
||||
* @param copyFromDB Database you want to backup.
|
||||
*/
|
||||
private void createNewBackup(String dbName, Database copyFromDB) {
|
||||
Integer userCount = copyFromDB.query(ServerAggregateQueries.baseUserCount());
|
||||
if (userCount <= 0) {
|
||||
return;
|
||||
}
|
||||
SQLiteDB backupDB = null;
|
||||
try {
|
||||
String timeStamp = iso8601LongFormatter.apply(System.currentTimeMillis());
|
||||
String fileName = dbName + "-backup-" + timeStamp;
|
||||
backupDB = sqliteFactory.usingFileCalled(fileName);
|
||||
Collection<UUID> uuids = copyFromDB.fetch().getSavedUUIDs();
|
||||
if (uuids.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
backupDB.init();
|
||||
copyFromDB.backup().backup(backupDB);
|
||||
} catch (DBException e) {
|
||||
backupDB.executeTransaction(new BackupCopyTransaction(copyFromDB, backupDB)).get();
|
||||
} catch (DBOpException | ExecutionException e) {
|
||||
errorHandler.log(L.ERROR, this.getClass(), e);
|
||||
} catch (InterruptedException e) {
|
||||
backupDB.close();
|
||||
Thread.currentThread().interrupt();
|
||||
} finally {
|
||||
if (backupDB != null) {
|
||||
backupDB.close();
|
||||
|
@ -18,9 +18,10 @@ package com.djrapitops.plan.command.commands.manage;
|
||||
|
||||
import com.djrapitops.plan.api.exceptions.database.DBInitException;
|
||||
import com.djrapitops.plan.api.exceptions.database.DBOpException;
|
||||
import com.djrapitops.plan.db.DBType;
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.db.access.transactions.commands.RemoveEverythingTransaction;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.database.databases.DBType;
|
||||
import com.djrapitops.plan.system.database.databases.Database;
|
||||
import com.djrapitops.plan.system.locale.Locale;
|
||||
import com.djrapitops.plan.system.locale.lang.CmdHelpLang;
|
||||
import com.djrapitops.plan.system.locale.lang.CommandLang;
|
||||
@ -101,7 +102,7 @@ public class ManageClearCommand extends CommandNode {
|
||||
try {
|
||||
sender.sendMessage(locale.getString(ManageLang.PROGRESS_START));
|
||||
|
||||
database.remove().everything();
|
||||
database.executeTransaction(new RemoveEverythingTransaction());
|
||||
|
||||
sender.sendMessage(locale.getString(ManageLang.PROGRESS_SUCCESS));
|
||||
} catch (DBOpException e) {
|
||||
|
@ -17,6 +17,8 @@
|
||||
package com.djrapitops.plan.command.commands.manage;
|
||||
|
||||
import com.djrapitops.plan.api.exceptions.connection.*;
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.db.access.queries.objects.ServerQueries;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.info.connection.ConnectionSystem;
|
||||
import com.djrapitops.plan.system.info.request.InfoRequestFactory;
|
||||
@ -38,7 +40,7 @@ import com.djrapitops.plugin.command.Sender;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
@ -122,19 +124,24 @@ public class ManageConDebugCommand extends CommandNode {
|
||||
return;
|
||||
}
|
||||
|
||||
Database.State dbState = dbSystem.getDatabase().getState();
|
||||
if (dbState != Database.State.OPEN) {
|
||||
sender.sendMessage(locale.getString(CommandLang.FAIL_DATABASE_NOT_OPEN, dbState.name()));
|
||||
return;
|
||||
}
|
||||
|
||||
processing.submitNonCritical(() -> testServers(sender));
|
||||
}
|
||||
|
||||
private void testServers(Sender sender) {
|
||||
List<Server> servers = dbSystem.getDatabase().fetch().getServers();
|
||||
Map<UUID, Server> servers = dbSystem.getDatabase().query(ServerQueries.fetchPlanServerInformation());
|
||||
|
||||
if (servers.isEmpty()) {
|
||||
sender.sendMessage(locale.getString(ManageLang.CON_NO_SERVERS));
|
||||
}
|
||||
|
||||
String accessAddress = webServer.getAccessAddress();
|
||||
UUID thisServer = serverInfo.getServerUUID();
|
||||
for (Server server : servers) {
|
||||
for (Server server : servers.values()) {
|
||||
if (thisServer.equals(server.getUuid())) {
|
||||
continue;
|
||||
}
|
||||
|
@ -17,9 +17,9 @@
|
||||
package com.djrapitops.plan.command.commands.manage;
|
||||
|
||||
import com.djrapitops.plan.PlanPlugin;
|
||||
import com.djrapitops.plan.db.DBType;
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.database.databases.DBType;
|
||||
import com.djrapitops.plan.system.database.databases.Database;
|
||||
import com.djrapitops.plan.system.locale.Locale;
|
||||
import com.djrapitops.plan.system.locale.lang.CmdHelpLang;
|
||||
import com.djrapitops.plan.system.locale.lang.CommandLang;
|
||||
@ -84,7 +84,7 @@ public class ManageHotSwapCommand extends CommandNode {
|
||||
Database database = dbSystem.getActiveDatabaseByName(dbName);
|
||||
database.init();
|
||||
|
||||
if (!database.isOpen()) {
|
||||
if (database.getState() == Database.State.CLOSED) {
|
||||
return;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
@ -16,6 +16,8 @@
|
||||
*/
|
||||
package com.djrapitops.plan.command.commands.manage;
|
||||
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.importing.ImportSystem;
|
||||
import com.djrapitops.plan.system.importing.importers.Importer;
|
||||
import com.djrapitops.plan.system.locale.Locale;
|
||||
@ -44,18 +46,21 @@ import java.util.Optional;
|
||||
public class ManageImportCommand extends CommandNode {
|
||||
|
||||
private final Locale locale;
|
||||
private final DBSystem dbSystem;
|
||||
private final Processing processing;
|
||||
private final ImportSystem importSystem;
|
||||
|
||||
@Inject
|
||||
public ManageImportCommand(
|
||||
Locale locale,
|
||||
DBSystem dbSystem,
|
||||
Processing processing,
|
||||
ImportSystem importSystem
|
||||
) {
|
||||
super("import", Permissions.MANAGE.getPermission(), CommandType.CONSOLE);
|
||||
|
||||
this.locale = locale;
|
||||
this.dbSystem = dbSystem;
|
||||
this.processing = processing;
|
||||
this.importSystem = importSystem;
|
||||
|
||||
@ -77,6 +82,12 @@ public class ManageImportCommand extends CommandNode {
|
||||
return;
|
||||
}
|
||||
|
||||
Database.State dbState = dbSystem.getDatabase().getState();
|
||||
if (dbState != Database.State.OPEN) {
|
||||
sender.sendMessage(locale.getString(CommandLang.FAIL_DATABASE_NOT_OPEN, dbState.name()));
|
||||
return;
|
||||
}
|
||||
|
||||
findAndProcessImporter(sender, importArg);
|
||||
}
|
||||
|
||||
|
@ -16,9 +16,10 @@
|
||||
*/
|
||||
package com.djrapitops.plan.command.commands.manage;
|
||||
|
||||
import com.djrapitops.plan.db.DBType;
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.db.access.transactions.BackupCopyTransaction;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.database.databases.DBType;
|
||||
import com.djrapitops.plan.system.database.databases.Database;
|
||||
import com.djrapitops.plan.system.locale.Locale;
|
||||
import com.djrapitops.plan.system.locale.lang.CmdHelpLang;
|
||||
import com.djrapitops.plan.system.locale.lang.CommandLang;
|
||||
@ -111,7 +112,7 @@ public class ManageMoveCommand extends CommandNode {
|
||||
try {
|
||||
sender.sendMessage(locale.getString(ManageLang.PROGRESS_START));
|
||||
|
||||
fromDatabase.backup().backup(toDatabase);
|
||||
toDatabase.executeTransaction(new BackupCopyTransaction(fromDatabase, toDatabase)).get();
|
||||
|
||||
sender.sendMessage(locale.getString(ManageLang.PROGRESS_SUCCESS));
|
||||
|
||||
@ -119,6 +120,8 @@ public class ManageMoveCommand extends CommandNode {
|
||||
if (movingToCurrentDB) {
|
||||
sender.sendMessage(locale.getString(ManageLang.HOTSWAP_REMINDER, toDatabase.getType().getConfigName()));
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
} catch (Exception e) {
|
||||
errorHandler.log(L.ERROR, this.getClass(), e);
|
||||
sender.sendMessage(locale.getString(ManageLang.PROGRESS_FAIL, e.getMessage()));
|
||||
|
@ -17,8 +17,10 @@
|
||||
package com.djrapitops.plan.command.commands.manage;
|
||||
|
||||
import com.djrapitops.plan.api.exceptions.database.DBOpException;
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.db.access.queries.PlayerFetchQueries;
|
||||
import com.djrapitops.plan.db.access.transactions.commands.RemovePlayerTransaction;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.database.databases.Database;
|
||||
import com.djrapitops.plan.system.locale.Locale;
|
||||
import com.djrapitops.plan.system.locale.lang.CmdHelpLang;
|
||||
import com.djrapitops.plan.system.locale.lang.CommandLang;
|
||||
@ -94,15 +96,15 @@ public class ManageRemoveCommand extends CommandNode {
|
||||
private void runRemoveTask(String playerName, Sender sender, String[] args) {
|
||||
processing.submitCritical(() -> {
|
||||
try {
|
||||
UUID uuid = uuidUtility.getUUIDOf(playerName);
|
||||
UUID playerUUID = uuidUtility.getUUIDOf(playerName);
|
||||
|
||||
if (uuid == null) {
|
||||
if (playerUUID == null) {
|
||||
sender.sendMessage(locale.getString(CommandLang.FAIL_USERNAME_NOT_VALID));
|
||||
return;
|
||||
}
|
||||
|
||||
Database db = dbSystem.getDatabase();
|
||||
if (!db.check().isPlayerRegistered(uuid)) {
|
||||
if (!db.query(PlayerFetchQueries.isPlayerRegistered(playerUUID))) {
|
||||
sender.sendMessage(locale.getString(CommandLang.FAIL_USERNAME_NOT_KNOWN));
|
||||
return;
|
||||
}
|
||||
@ -118,7 +120,7 @@ public class ManageRemoveCommand extends CommandNode {
|
||||
|
||||
sender.sendMessage(locale.getString(ManageLang.PROGRESS_START));
|
||||
|
||||
db.remove().player(uuid);
|
||||
db.executeTransaction(new RemovePlayerTransaction(playerUUID));
|
||||
|
||||
sender.sendMessage(locale.getString(ManageLang.PROGRESS_SUCCESS));
|
||||
} catch (DBOpException e) {
|
||||
|
@ -16,10 +16,11 @@
|
||||
*/
|
||||
package com.djrapitops.plan.command.commands.manage;
|
||||
|
||||
import com.djrapitops.plan.db.DBType;
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.db.SQLiteDB;
|
||||
import com.djrapitops.plan.db.access.transactions.BackupCopyTransaction;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.database.databases.DBType;
|
||||
import com.djrapitops.plan.system.database.databases.Database;
|
||||
import com.djrapitops.plan.system.database.databases.sql.SQLiteDB;
|
||||
import com.djrapitops.plan.system.file.PlanFiles;
|
||||
import com.djrapitops.plan.system.locale.Locale;
|
||||
import com.djrapitops.plan.system.locale.lang.CmdHelpLang;
|
||||
@ -121,11 +122,18 @@ public class ManageRestoreCommand extends CommandNode {
|
||||
SQLiteDB backupDB = sqliteFactory.usingFile(backupDBFile);
|
||||
backupDB.init();
|
||||
|
||||
Database.State dbState = database.getState();
|
||||
if (dbState != Database.State.OPEN) {
|
||||
sender.sendMessage(locale.getString(CommandLang.WARN_DATABASE_NOT_OPEN, dbState.name()));
|
||||
}
|
||||
|
||||
sender.sendMessage(locale.getString(ManageLang.PROGRESS_START));
|
||||
|
||||
database.backup().restore(backupDB);
|
||||
database.executeTransaction(new BackupCopyTransaction(backupDB, database)).get();
|
||||
|
||||
sender.sendMessage(locale.getString(ManageLang.PROGRESS_SUCCESS));
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
} catch (Exception e) {
|
||||
errorHandler.log(L.ERROR, this.getClass(), e);
|
||||
sender.sendMessage(locale.getString(ManageLang.PROGRESS_FAIL, e.getMessage()));
|
||||
|
@ -17,11 +17,15 @@
|
||||
package com.djrapitops.plan.command.commands.manage;
|
||||
|
||||
import com.djrapitops.plan.api.exceptions.database.DBOpException;
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.db.access.queries.objects.ServerQueries;
|
||||
import com.djrapitops.plan.db.access.transactions.commands.SetServerAsUninstalledTransaction;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.info.server.Server;
|
||||
import com.djrapitops.plan.system.info.server.ServerInfo;
|
||||
import com.djrapitops.plan.system.locale.Locale;
|
||||
import com.djrapitops.plan.system.locale.lang.CmdHelpLang;
|
||||
import com.djrapitops.plan.system.locale.lang.CommandLang;
|
||||
import com.djrapitops.plan.system.locale.lang.DeepHelpLang;
|
||||
import com.djrapitops.plan.system.locale.lang.ManageLang;
|
||||
import com.djrapitops.plan.system.processing.Processing;
|
||||
@ -34,7 +38,6 @@ import com.djrapitops.plugin.logging.error.ErrorHandler;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
@ -77,6 +80,12 @@ public class ManageUninstalledCommand extends CommandNode {
|
||||
public void onCommand(Sender sender, String commandLabel, String[] args) {
|
||||
sender.sendMessage(locale.getString(ManageLang.PROGRESS_START));
|
||||
|
||||
Database.State dbState = dbSystem.getDatabase().getState();
|
||||
if (dbState != Database.State.OPEN) {
|
||||
sender.sendMessage(locale.getString(CommandLang.FAIL_DATABASE_NOT_OPEN, dbState.name()));
|
||||
return;
|
||||
}
|
||||
|
||||
processing.submitNonCritical(() -> {
|
||||
try {
|
||||
Optional<Server> serverOptional = getServer(args);
|
||||
@ -91,7 +100,7 @@ public class ManageUninstalledCommand extends CommandNode {
|
||||
return;
|
||||
}
|
||||
|
||||
dbSystem.getDatabase().save().setAsUninstalled(serverUUID);
|
||||
dbSystem.getDatabase().executeTransaction(new SetServerAsUninstalledTransaction(serverUUID));
|
||||
sender.sendMessage(locale.getString(ManageLang.PROGRESS_SUCCESS));
|
||||
} catch (DBOpException e) {
|
||||
sender.sendMessage("§cError occurred: " + e.toString());
|
||||
@ -102,16 +111,9 @@ public class ManageUninstalledCommand extends CommandNode {
|
||||
|
||||
private Optional<Server> getServer(String[] args) {
|
||||
if (args.length >= 1) {
|
||||
Map<UUID, Server> bukkitServers = dbSystem.getDatabase().fetch().getBukkitServers();
|
||||
String serverIdentifier = getGivenIdentifier(args);
|
||||
for (Map.Entry<UUID, Server> entry : bukkitServers.entrySet()) {
|
||||
Server server = entry.getValue();
|
||||
|
||||
if (Integer.toString(server.getId()).equals(serverIdentifier)
|
||||
|| server.getName().equalsIgnoreCase(serverIdentifier)) {
|
||||
return Optional.of(server);
|
||||
}
|
||||
}
|
||||
return dbSystem.getDatabase().query(ServerQueries.fetchServerMatchingIdentifier(serverIdentifier))
|
||||
.filter(Server::isNotProxy);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
@ -17,8 +17,9 @@
|
||||
package com.djrapitops.plan.command.commands.webuser;
|
||||
|
||||
import com.djrapitops.plan.data.WebUser;
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.db.access.queries.objects.WebUserQueries;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.database.databases.Database;
|
||||
import com.djrapitops.plan.system.locale.Locale;
|
||||
import com.djrapitops.plan.system.locale.lang.CmdHelpLang;
|
||||
import com.djrapitops.plan.system.locale.lang.CommandLang;
|
||||
@ -35,6 +36,7 @@ import com.djrapitops.plugin.utilities.Verify;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Subcommand for checking WebUser permission level.
|
||||
@ -69,6 +71,12 @@ public class WebCheckCommand extends CommandNode {
|
||||
|
||||
@Override
|
||||
public void onCommand(Sender sender, String commandLabel, String[] args) {
|
||||
Database.State dbState = dbSystem.getDatabase().getState();
|
||||
if (dbState != Database.State.OPEN) {
|
||||
sender.sendMessage(locale.getString(CommandLang.FAIL_DATABASE_NOT_OPEN, dbState.name()));
|
||||
return;
|
||||
}
|
||||
|
||||
Verify.isTrue(args.length >= 1,
|
||||
() -> new IllegalArgumentException(locale.getString(CommandLang.FAIL_REQ_ONE_ARG, Arrays.toString(this.getArguments()))));
|
||||
|
||||
@ -77,11 +85,12 @@ public class WebCheckCommand extends CommandNode {
|
||||
processing.submitNonCritical(() -> {
|
||||
try {
|
||||
Database db = dbSystem.getDatabase();
|
||||
if (!db.check().doesWebUserExists(user)) {
|
||||
Optional<WebUser> found = db.query(WebUserQueries.fetchWebUser(user));
|
||||
if (!found.isPresent()) {
|
||||
sender.sendMessage(locale.getString(CommandLang.FAIL_WEB_USER_NOT_EXISTS));
|
||||
return;
|
||||
}
|
||||
WebUser info = db.fetch().getWebUser(user);
|
||||
WebUser info = found.get();
|
||||
sender.sendMessage(locale.getString(CommandLang.WEB_USER_LIST, info.getName(), info.getPermLevel()));
|
||||
} catch (Exception e) {
|
||||
errorHandler.log(L.ERROR, this.getClass(), e);
|
||||
|
@ -16,8 +16,11 @@
|
||||
*/
|
||||
package com.djrapitops.plan.command.commands.webuser;
|
||||
|
||||
import com.djrapitops.plan.data.WebUser;
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.db.access.queries.objects.WebUserQueries;
|
||||
import com.djrapitops.plan.db.access.transactions.commands.RemoveWebUserTransaction;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.database.databases.Database;
|
||||
import com.djrapitops.plan.system.locale.Locale;
|
||||
import com.djrapitops.plan.system.locale.lang.CmdHelpLang;
|
||||
import com.djrapitops.plan.system.locale.lang.CommandLang;
|
||||
@ -34,6 +37,7 @@ import com.djrapitops.plugin.utilities.Verify;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Subcommand for deleting a WebUser.
|
||||
@ -68,6 +72,12 @@ public class WebDeleteCommand extends CommandNode {
|
||||
|
||||
@Override
|
||||
public void onCommand(Sender sender, String commandLabel, String[] args) {
|
||||
Database.State dbState = dbSystem.getDatabase().getState();
|
||||
if (dbState != Database.State.OPEN) {
|
||||
sender.sendMessage(locale.getString(CommandLang.FAIL_DATABASE_NOT_OPEN, dbState.name()));
|
||||
return;
|
||||
}
|
||||
|
||||
Verify.isTrue(args.length >= 1,
|
||||
() -> new IllegalArgumentException(locale.getString(CommandLang.FAIL_REQ_ONE_ARG, Arrays.toString(this.getArguments()))));
|
||||
|
||||
@ -76,11 +86,12 @@ public class WebDeleteCommand extends CommandNode {
|
||||
processing.submitNonCritical(() -> {
|
||||
try {
|
||||
Database db = dbSystem.getDatabase();
|
||||
if (!db.check().doesWebUserExists(user)) {
|
||||
Optional<WebUser> found = db.query(WebUserQueries.fetchWebUser(user));
|
||||
if (!found.isPresent()) {
|
||||
sender.sendMessage("§c[Plan] User Doesn't exist.");
|
||||
return;
|
||||
}
|
||||
db.remove().webUser(user);
|
||||
db.executeTransaction(new RemoveWebUserTransaction(user));
|
||||
sender.sendMessage(locale.getString(ManageLang.PROGRESS_SUCCESS));
|
||||
} catch (Exception e) {
|
||||
errorHandler.log(L.ERROR, this.getClass(), e);
|
||||
|
@ -17,6 +17,8 @@
|
||||
package com.djrapitops.plan.command.commands.webuser;
|
||||
|
||||
import com.djrapitops.plan.data.WebUser;
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.db.access.queries.objects.WebUserQueries;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.locale.Locale;
|
||||
import com.djrapitops.plan.system.locale.lang.CmdHelpLang;
|
||||
@ -24,7 +26,6 @@ import com.djrapitops.plan.system.locale.lang.CommandLang;
|
||||
import com.djrapitops.plan.system.locale.lang.ManageLang;
|
||||
import com.djrapitops.plan.system.processing.Processing;
|
||||
import com.djrapitops.plan.system.settings.Permissions;
|
||||
import com.djrapitops.plan.utilities.comparators.WebUserComparator;
|
||||
import com.djrapitops.plugin.command.CommandNode;
|
||||
import com.djrapitops.plugin.command.CommandType;
|
||||
import com.djrapitops.plugin.command.Sender;
|
||||
@ -67,10 +68,15 @@ public class WebListUsersCommand extends CommandNode {
|
||||
|
||||
@Override
|
||||
public void onCommand(Sender sender, String commandLabel, String[] args) {
|
||||
Database.State dbState = dbSystem.getDatabase().getState();
|
||||
if (dbState != Database.State.OPEN) {
|
||||
sender.sendMessage(locale.getString(CommandLang.FAIL_DATABASE_NOT_OPEN, dbState.name()));
|
||||
return;
|
||||
}
|
||||
|
||||
processing.submitNonCritical(() -> {
|
||||
try {
|
||||
List<WebUser> users = dbSystem.getDatabase().fetch().getWebUsers();
|
||||
users.sort(new WebUserComparator());
|
||||
List<WebUser> users = dbSystem.getDatabase().query(WebUserQueries.fetchAllPlanWebUsers());
|
||||
sender.sendMessage(locale.getString(CommandLang.HEADER_WEB_USERS, users.size()));
|
||||
for (WebUser user : users) {
|
||||
sender.sendMessage(locale.getString(CommandLang.WEB_USER_LIST, user.getName(), user.getPermLevel()));
|
||||
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.data.container;
|
||||
|
||||
import com.djrapitops.plugin.utilities.Verify;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Represents user information stored in plan_users.
|
||||
* <p>
|
||||
* Only one per player exists unlike {@link UserInfo} which is available per server.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class BaseUser {
|
||||
|
||||
private final UUID uuid;
|
||||
private final String name;
|
||||
private final long registered;
|
||||
private final int timesKicked;
|
||||
|
||||
public BaseUser(UUID uuid, String name, long registered, int timesKicked) {
|
||||
Verify.nullCheck(uuid, () -> new IllegalArgumentException("'uuid' can not be null"));
|
||||
Verify.nullCheck(name, () -> new IllegalArgumentException("'name' can not be null"));
|
||||
|
||||
this.uuid = uuid;
|
||||
this.name = name;
|
||||
this.registered = registered;
|
||||
this.timesKicked = timesKicked;
|
||||
}
|
||||
|
||||
public UUID getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public long getRegistered() {
|
||||
return registered;
|
||||
}
|
||||
|
||||
public int getTimesKicked() {
|
||||
return timesKicked;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof BaseUser)) return false;
|
||||
BaseUser baseUser = (BaseUser) o;
|
||||
return registered == baseUser.registered &&
|
||||
timesKicked == baseUser.timesKicked &&
|
||||
uuid.equals(baseUser.uuid) &&
|
||||
name.equals(baseUser.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(uuid, name, registered, timesKicked);
|
||||
}
|
||||
}
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
package com.djrapitops.plan.data.container;
|
||||
|
||||
import com.djrapitops.plan.data.store.containers.DataContainer;
|
||||
import com.djrapitops.plan.data.store.containers.DynamicDataContainer;
|
||||
import com.djrapitops.plan.data.store.keys.SessionKeys;
|
||||
import com.djrapitops.plan.data.store.objects.DateHolder;
|
||||
import com.djrapitops.plan.data.time.WorldTimes;
|
||||
@ -29,7 +29,7 @@ import java.util.*;
|
||||
* @author Rsl1122
|
||||
* @see SessionKeys for Key objects.
|
||||
*/
|
||||
public class Session extends DataContainer implements DateHolder {
|
||||
public class Session extends DynamicDataContainer implements DateHolder {
|
||||
|
||||
private long sessionStart;
|
||||
private WorldTimes worldTimes;
|
||||
@ -228,4 +228,17 @@ public class Session extends DataContainer implements DateHolder {
|
||||
private long getAfkTime() {
|
||||
return afkTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Session{" +
|
||||
"sessionStart=" + getUnsafe(SessionKeys.START) +
|
||||
", sessionEnd=" + getUnsafe(SessionKeys.END) +
|
||||
", worldTimes=" + worldTimes +
|
||||
", playerKills=" + playerKills +
|
||||
", mobKills=" + mobKills +
|
||||
", deaths=" + deaths +
|
||||
", afkTime=" + afkTime +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
@ -20,48 +20,41 @@ import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Used for storing information of players after it has been fetched.
|
||||
* Represents user information stored in plan_user_info.
|
||||
* <p>
|
||||
* Unlike {@link BaseUser} one instance is stored per server for a single player.
|
||||
* Proxy servers are an exception, and UserInfo is not stored for them.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class UserInfo {
|
||||
|
||||
private final UUID uuid;
|
||||
private String name;
|
||||
private final UUID playerUUID;
|
||||
private final UUID serverUUID;
|
||||
private long registered;
|
||||
private long lastSeen;
|
||||
private boolean banned;
|
||||
private boolean opped;
|
||||
|
||||
public UserInfo(UUID uuid, String name, long registered, boolean opped, boolean banned) {
|
||||
this.uuid = uuid;
|
||||
this.name = name;
|
||||
public UserInfo(UUID playerUUID, UUID serverUUID, long registered, boolean opped, boolean banned) {
|
||||
this.playerUUID = playerUUID;
|
||||
this.serverUUID = serverUUID;
|
||||
this.registered = registered;
|
||||
this.opped = opped;
|
||||
this.banned = banned;
|
||||
lastSeen = 0L;
|
||||
}
|
||||
|
||||
public UUID getUuid() {
|
||||
return uuid;
|
||||
public UUID getPlayerUuid() {
|
||||
return playerUUID;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
public UUID getServerUUID() {
|
||||
return serverUUID;
|
||||
}
|
||||
|
||||
public long getRegistered() {
|
||||
return registered;
|
||||
}
|
||||
|
||||
public long getLastSeen() {
|
||||
return lastSeen;
|
||||
}
|
||||
|
||||
public void setLastSeen(long lastSeen) {
|
||||
this.lastSeen = lastSeen;
|
||||
}
|
||||
|
||||
public boolean isBanned() {
|
||||
return banned;
|
||||
}
|
||||
@ -73,28 +66,26 @@ public class UserInfo {
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
if (!(o instanceof UserInfo)) return false;
|
||||
UserInfo userInfo = (UserInfo) o;
|
||||
return registered == userInfo.registered &&
|
||||
lastSeen == userInfo.lastSeen &&
|
||||
banned == userInfo.banned &&
|
||||
opped == userInfo.opped &&
|
||||
Objects.equals(uuid, userInfo.uuid) &&
|
||||
Objects.equals(name, userInfo.name);
|
||||
playerUUID.equals(userInfo.playerUUID) &&
|
||||
serverUUID.equals(userInfo.serverUUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(uuid, name, registered, lastSeen, banned, opped);
|
||||
return Objects.hash(playerUUID, serverUUID, registered, banned, opped);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "UserInfo{" +
|
||||
"uuid=" + uuid +
|
||||
", name='" + name + '\'' +
|
||||
"playerUUID=" + playerUUID +
|
||||
", serverUUID=" + serverUUID +
|
||||
", registered=" + registered +
|
||||
", lastSeen=" + lastSeen +
|
||||
", banned=" + banned +
|
||||
", opped=" + opped +
|
||||
'}';
|
||||
|
@ -125,8 +125,9 @@ public class HookHandler implements SubSystem {
|
||||
containers.put(pluginData, container);
|
||||
}
|
||||
} catch (Exception | NoClassDefFoundError | NoSuchFieldError | NoSuchMethodError e) {
|
||||
String sourcePlugin = pluginData.getSourcePlugin();
|
||||
logger.error("PluginData caused exception: " + sourcePlugin);
|
||||
String pluginName = pluginData.getSourcePlugin();
|
||||
logger.error("PluginData caused exception: " + pluginName +
|
||||
", you can disable the integration under 'Plugins." + pluginName + ".Enabled'");
|
||||
errorHandler.log(L.WARN, pluginData.getClass(), e);
|
||||
}
|
||||
}
|
||||
|
@ -81,4 +81,17 @@ public class Key<T> {
|
||||
public int hashCode() {
|
||||
return Objects.hash(type, keyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cast an object to the type of the key.
|
||||
*
|
||||
* @param object Object to cast.
|
||||
* @return The object with the type of T.
|
||||
*/
|
||||
public T typeCast(Object object) {
|
||||
// Since Type can have a List<Subtype>, Class can not be obtained in order to use Class while casting.
|
||||
// This could be done since Google Gson does it, but I don't know how they do it since
|
||||
// the implementation is hidden.
|
||||
return (T) object;
|
||||
}
|
||||
}
|
@ -24,7 +24,6 @@ import com.djrapitops.plan.data.store.keys.ServerKeys;
|
||||
import com.djrapitops.plan.data.store.mutators.*;
|
||||
import com.djrapitops.plan.data.store.mutators.health.HealthInformation;
|
||||
import com.djrapitops.plan.data.time.WorldTimes;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.info.server.properties.ServerProperties;
|
||||
import com.djrapitops.plan.system.locale.Locale;
|
||||
import com.djrapitops.plan.system.settings.config.PlanConfig;
|
||||
@ -59,7 +58,7 @@ import java.util.stream.Collectors;
|
||||
* @see com.djrapitops.plan.data.store.keys.AnalysisKeys for Key objects
|
||||
* @see com.djrapitops.plan.data.store.PlaceholderKey for placeholder information
|
||||
*/
|
||||
public class AnalysisContainer extends DataContainer {
|
||||
public class AnalysisContainer extends DynamicDataContainer {
|
||||
|
||||
private final ServerContainer serverContainer;
|
||||
|
||||
@ -67,7 +66,6 @@ public class AnalysisContainer extends DataContainer {
|
||||
private final Locale locale;
|
||||
private final PlanConfig config;
|
||||
private final Theme theme;
|
||||
private final DBSystem dbSystem;
|
||||
private final ServerProperties serverProperties;
|
||||
private final Formatters formatters;
|
||||
private final Graphs graphs;
|
||||
@ -75,16 +73,12 @@ public class AnalysisContainer extends DataContainer {
|
||||
private final Accordions accordions;
|
||||
private final AnalysisPluginsTabContentCreator pluginsTabContentCreator;
|
||||
|
||||
private static final Key<Map<UUID, String>> serverNames = new Key<>(new Type<Map<UUID, String>>() {
|
||||
}, "SERVER_NAMES");
|
||||
|
||||
public AnalysisContainer(
|
||||
ServerContainer serverContainer,
|
||||
String version,
|
||||
Locale locale,
|
||||
PlanConfig config,
|
||||
Theme theme,
|
||||
DBSystem dbSystem,
|
||||
ServerProperties serverProperties,
|
||||
Formatters formatters,
|
||||
Graphs graphs,
|
||||
@ -97,7 +91,6 @@ public class AnalysisContainer extends DataContainer {
|
||||
this.locale = locale;
|
||||
this.config = config;
|
||||
this.theme = theme;
|
||||
this.dbSystem = dbSystem;
|
||||
this.serverProperties = serverProperties;
|
||||
this.formatters = formatters;
|
||||
this.graphs = graphs;
|
||||
@ -148,9 +141,7 @@ public class AnalysisContainer extends DataContainer {
|
||||
}
|
||||
|
||||
private void addServerProperties() {
|
||||
putCachingSupplier(AnalysisKeys.SERVER_NAME, () ->
|
||||
getUnsafe(serverNames).getOrDefault(serverContainer.getUnsafe(ServerKeys.SERVER_UUID), "Plan")
|
||||
);
|
||||
putCachingSupplier(AnalysisKeys.SERVER_NAME, () -> serverContainer.getValue(ServerKeys.NAME).orElse("Plan"));
|
||||
|
||||
putRawData(AnalysisKeys.PLAYERS_MAX, serverProperties.getMaxPlayers());
|
||||
putRawData(AnalysisKeys.PLAYERS_ONLINE, serverProperties.getOnlinePlayers());
|
||||
@ -308,10 +299,12 @@ public class AnalysisContainer extends DataContainer {
|
||||
|
||||
private void addSessionSuppliers() {
|
||||
Key<SessionAccordion> sessionAccordion = new Key<>(SessionAccordion.class, "SESSION_ACCORDION");
|
||||
putCachingSupplier(serverNames, () -> dbSystem.getDatabase().fetch().getServerNames());
|
||||
putCachingSupplier(sessionAccordion, () -> accordions.serverSessionAccordion(
|
||||
getUnsafe(AnalysisKeys.SESSIONS_MUTATOR).all(),
|
||||
getSupplier(serverNames),
|
||||
() -> Collections.singletonMap(
|
||||
serverContainer.getUnsafe(ServerKeys.SERVER_UUID),
|
||||
serverContainer.getValue(ServerKeys.NAME).orElse("This server")
|
||||
),
|
||||
() -> getUnsafe(AnalysisKeys.PLAYER_NAMES)
|
||||
));
|
||||
putSupplier(AnalysisKeys.SESSION_ACCORDION_HTML, () -> getUnsafe(sessionAccordion).toHtml());
|
||||
@ -511,7 +504,6 @@ public class AnalysisContainer extends DataContainer {
|
||||
private final PlanConfig config;
|
||||
private final Locale locale;
|
||||
private final Theme theme;
|
||||
private final DBSystem dbSystem;
|
||||
private final ServerProperties serverProperties;
|
||||
private final Formatters formatters;
|
||||
private final Graphs graphs;
|
||||
@ -525,7 +517,6 @@ public class AnalysisContainer extends DataContainer {
|
||||
PlanConfig config,
|
||||
Locale locale,
|
||||
Theme theme,
|
||||
DBSystem dbSystem,
|
||||
ServerProperties serverProperties,
|
||||
Formatters formatters,
|
||||
Graphs graphs,
|
||||
@ -537,7 +528,6 @@ public class AnalysisContainer extends DataContainer {
|
||||
this.config = config;
|
||||
this.locale = locale;
|
||||
this.theme = theme;
|
||||
this.dbSystem = dbSystem;
|
||||
this.serverProperties = serverProperties;
|
||||
this.formatters = formatters;
|
||||
this.graphs = graphs;
|
||||
@ -553,7 +543,6 @@ public class AnalysisContainer extends DataContainer {
|
||||
locale,
|
||||
config,
|
||||
theme,
|
||||
dbSystem,
|
||||
serverProperties,
|
||||
formatters,
|
||||
graphs,
|
||||
|
@ -16,66 +16,56 @@
|
||||
*/
|
||||
package com.djrapitops.plan.data.store.containers;
|
||||
|
||||
import com.djrapitops.plan.data.store.CachingSupplier;
|
||||
import com.djrapitops.plan.data.store.Key;
|
||||
import com.djrapitops.plan.utilities.formatting.Formatter;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Abstract representation of an object that holds the Values for different Keys.
|
||||
* Interface for an object that can store arbitrary data referenced via {@link Key} objects.
|
||||
* <p>
|
||||
* The methods in this object are used for placing and fetching the data from the container.
|
||||
* Methods to use depend on your use case.
|
||||
* Implementations should mainly be concerned on how the data given to it is stored.
|
||||
* Retrieval has some details that should be followed.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class DataContainer {
|
||||
|
||||
private final Map<Key, Supplier> map;
|
||||
private long timeToLive;
|
||||
|
||||
public DataContainer() {
|
||||
this(TimeUnit.SECONDS.toMillis(30L));
|
||||
}
|
||||
|
||||
public DataContainer(long timeToLive) {
|
||||
this.timeToLive = timeToLive;
|
||||
map = new HashMap<>();
|
||||
}
|
||||
public interface DataContainer {
|
||||
|
||||
/**
|
||||
* Place your data inside the container.
|
||||
* <p>
|
||||
* What the container does with the object depends on the implementation.
|
||||
*
|
||||
* @param key Key of type T that identifies the data and will be used later when the data needs to be fetched.
|
||||
* @param obj object to store
|
||||
* @param <T> Type of the object
|
||||
*/
|
||||
public <T> void putRawData(Key<T> key, T obj) {
|
||||
putSupplier(key, () -> obj);
|
||||
}
|
||||
<T> void putRawData(Key<T> key, T obj);
|
||||
|
||||
public <T> void putSupplier(Key<T> key, Supplier<T> supplier) {
|
||||
if (supplier == null) {
|
||||
return;
|
||||
}
|
||||
map.put(key, supplier);
|
||||
}
|
||||
/**
|
||||
* Place a data supplier inside the container.
|
||||
* <p>
|
||||
* What the container does with the supplier depends on the implementation.
|
||||
*
|
||||
* @param key Key of type T that identifies the data and will be used later when the data needs to be fetched.
|
||||
* @param supplier Supplier to store
|
||||
* @param <T> Type of the object
|
||||
*/
|
||||
<T> void putSupplier(Key<T> key, Supplier<T> supplier);
|
||||
|
||||
public <T> void putCachingSupplier(Key<T> key, Supplier<T> supplier) {
|
||||
if (supplier == null) {
|
||||
return;
|
||||
}
|
||||
map.put(key, new CachingSupplier<>(supplier, timeToLive));
|
||||
}
|
||||
|
||||
public <T> Supplier<T> getSupplier(Key<T> key) {
|
||||
return (Supplier<T>) map.get(key);
|
||||
}
|
||||
/**
|
||||
* Place a caching data supplier inside the container.
|
||||
* <p>
|
||||
* If the supplier is called the value is cached according to the implementation of the container.
|
||||
* What the container does with the supplier depends on the implementation.
|
||||
*
|
||||
* @param key Key of type T that identifies the data and will be used later when the data needs to be fetched.
|
||||
* @param supplier Supplier to store
|
||||
* @param <T> Type of the object
|
||||
*/
|
||||
<T> void putCachingSupplier(Key<T> key, Supplier<T> supplier);
|
||||
|
||||
/**
|
||||
* Check if a Value with the given Key has been placed into the container.
|
||||
@ -84,65 +74,79 @@ public class DataContainer {
|
||||
* @param <T> Type of the object returned by the Value if it is present.
|
||||
* @return true if found, false if not.
|
||||
*/
|
||||
public <T> boolean supports(Key<T> key) {
|
||||
return map.containsKey(key);
|
||||
}
|
||||
<T> boolean supports(Key<T> key);
|
||||
|
||||
/**
|
||||
* Get an Optional of the data identified by the Key.
|
||||
* Get an Optional of the Value identified by the Key.
|
||||
* <p>
|
||||
* Since Value is a functional interface, its method may call blocking methods via Value implementations,
|
||||
* It is therefore recommended to not call this method on the server thread.
|
||||
* <p>
|
||||
* It is recommended to check if the Optional is present as null values returned by plugins will be empty.
|
||||
* It is recommended to check if the Optional is present as null values will be empty.
|
||||
*
|
||||
* @param key Key that identifies the Value
|
||||
* @param <T> Type of the object returned by Value
|
||||
* @return Optional of the object if the key is registered and key matches the type of the object. Otherwise empty.
|
||||
*/
|
||||
public <T> Optional<T> getValue(Key<T> key) {
|
||||
Supplier<T> supplier = getSupplier(key);
|
||||
if (supplier == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
try {
|
||||
return Optional.ofNullable(supplier.get());
|
||||
} catch (ClassCastException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
<T> Optional<T> getValue(Key<T> key);
|
||||
|
||||
public <T> T getUnsafe(Key<T> key) {
|
||||
Supplier supplier = map.get(key);
|
||||
if (supplier == null) {
|
||||
throw new IllegalArgumentException("Unsupported Key: " + key.getKeyName());
|
||||
}
|
||||
return (T) supplier.get();
|
||||
}
|
||||
/**
|
||||
* Get data identified by the Key, or throw an exception.
|
||||
* <p>
|
||||
* It is recommended to use {@link DataContainer#supports(Key)} before using this method.
|
||||
*
|
||||
* @param key Key that identifies the Value
|
||||
* @param <T> Type of the object returned by Value
|
||||
* @return the value
|
||||
* @throws IllegalArgumentException If the key is not supported.
|
||||
*/
|
||||
<T> T getUnsafe(Key<T> key);
|
||||
|
||||
public <T> String getFormatted(Key<T> key, Formatter<Optional<T>> formatter) {
|
||||
/**
|
||||
* Get formatted Value identified by the Key.
|
||||
* <p>
|
||||
*
|
||||
* @param key Key that identifies the Value
|
||||
* @param formatter Formatter for the Optional returned by {@link DataContainer#getValue(Key)}
|
||||
* @param <T> Type of the object returned by Value
|
||||
* @return Optional of the object if the key is registered and key matches the type of the object. Otherwise empty.
|
||||
*/
|
||||
default <T> String getFormatted(Key<T> key, Formatter<Optional<T>> formatter) {
|
||||
Optional<T> value = getValue(key);
|
||||
return formatter.apply(value);
|
||||
}
|
||||
|
||||
public <T> String getFormattedUnsafe(Key<T> key, Formatter<T> formatter) {
|
||||
/**
|
||||
* Get formatted Value identified by the Key, or throw an exception.
|
||||
* <p>
|
||||
* It is recommended to use {@link DataContainer#supports(Key)} before using this method.
|
||||
*
|
||||
* @param key Key that identifies the Value
|
||||
* @param formatter Formatter for the value
|
||||
* @param <T> Type of the object returned by Value
|
||||
* @return the value
|
||||
* @throws IllegalArgumentException If the key is not supported.
|
||||
*/
|
||||
default <T> String getFormattedUnsafe(Key<T> key, Formatter<T> formatter) {
|
||||
T value = getUnsafe(key);
|
||||
return formatter.apply(value);
|
||||
}
|
||||
|
||||
public void putAll(Map<Key, Supplier> toPut) {
|
||||
map.putAll(toPut);
|
||||
}
|
||||
/**
|
||||
* Place all values from given DataContainer into this container.
|
||||
*
|
||||
* @param dataContainer Container with values.
|
||||
*/
|
||||
void putAll(DataContainer dataContainer);
|
||||
|
||||
public void putAll(DataContainer dataContainer) {
|
||||
putAll(dataContainer.map);
|
||||
}
|
||||
/**
|
||||
* Clear the container of all data.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
public void clear() {
|
||||
map.clear();
|
||||
}
|
||||
|
||||
public Map<Key, Supplier> getMap() {
|
||||
return map;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Return a Key - Value Map of the data in the container.
|
||||
* <p>
|
||||
* This method may call blocking methods if underlying implementation uses the given Suppliers.
|
||||
*
|
||||
* @return Map: Key - Object
|
||||
*/
|
||||
Map<Key, Object> getMap();
|
||||
}
|
||||
|
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* 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.data.store.containers;
|
||||
|
||||
import com.djrapitops.plan.data.store.Key;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* DataContainer implementation that delegates the method calls to other DataContainer implementations.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class DynamicDataContainer implements DataContainer {
|
||||
|
||||
private final SupplierDataContainer supplierDataContainer;
|
||||
private final RawDataContainer rawDataContainer;
|
||||
|
||||
public DynamicDataContainer() {
|
||||
supplierDataContainer = new SupplierDataContainer();
|
||||
rawDataContainer = new RawDataContainer();
|
||||
}
|
||||
|
||||
public DynamicDataContainer(long timeToLive) {
|
||||
supplierDataContainer = new SupplierDataContainer(timeToLive);
|
||||
rawDataContainer = new RawDataContainer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void putRawData(Key<T> key, T obj) {
|
||||
rawDataContainer.putRawData(key, obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void putSupplier(Key<T> key, Supplier<T> supplier) {
|
||||
supplierDataContainer.putSupplier(key, supplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void putCachingSupplier(Key<T> key, Supplier<T> supplier) {
|
||||
supplierDataContainer.putCachingSupplier(key, supplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> boolean supports(Key<T> key) {
|
||||
return rawDataContainer.supports(key) || supplierDataContainer.supports(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Optional<T> getValue(Key<T> key) {
|
||||
Optional<T> raw = rawDataContainer.getValue(key);
|
||||
if (raw.isPresent()) {
|
||||
return raw;
|
||||
} else {
|
||||
return supplierDataContainer.getValue(key);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getUnsafe(Key<T> key) {
|
||||
if (rawDataContainer.supports(key)) {
|
||||
return rawDataContainer.getUnsafe(key);
|
||||
} else {
|
||||
return supplierDataContainer.getUnsafe(key);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(DataContainer dataContainer) {
|
||||
if (dataContainer instanceof SupplierDataContainer) {
|
||||
supplierDataContainer.putAll(dataContainer);
|
||||
} else if (dataContainer instanceof RawDataContainer) {
|
||||
rawDataContainer.putAll(dataContainer);
|
||||
} else {
|
||||
rawDataContainer.putAll(dataContainer.getMap());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
rawDataContainer.clear();
|
||||
supplierDataContainer.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Key, Object> getMap() {
|
||||
Map<Key, Object> map = supplierDataContainer.getMap();
|
||||
map.putAll(rawDataContainer.getMap());
|
||||
return map;
|
||||
}
|
||||
}
|
@ -23,6 +23,9 @@ import com.djrapitops.plan.data.store.keys.ServerKeys;
|
||||
import com.djrapitops.plan.data.store.mutators.PlayersMutator;
|
||||
import com.djrapitops.plan.data.store.mutators.TPSMutator;
|
||||
import com.djrapitops.plan.data.store.mutators.health.NetworkHealthInformation;
|
||||
import com.djrapitops.plan.db.Database;
|
||||
import com.djrapitops.plan.db.access.queries.ServerAggregateQueries;
|
||||
import com.djrapitops.plan.db.access.queries.objects.TPSQueries;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.info.server.Server;
|
||||
import com.djrapitops.plan.system.info.server.properties.ServerProperties;
|
||||
@ -54,7 +57,7 @@ import java.util.concurrent.TimeUnit;
|
||||
* @see com.djrapitops.plan.data.store.keys.NetworkKeys for Key objects
|
||||
* @see com.djrapitops.plan.data.store.PlaceholderKey for placeholder information
|
||||
*/
|
||||
public class NetworkContainer extends DataContainer {
|
||||
public class NetworkContainer extends DynamicDataContainer {
|
||||
|
||||
private final ServerContainer bungeeContainer;
|
||||
|
||||
@ -62,10 +65,10 @@ public class NetworkContainer extends DataContainer {
|
||||
private final PlanConfig config;
|
||||
private final Locale locale;
|
||||
private final Theme theme;
|
||||
private final DBSystem dbSystem;
|
||||
private final ServerProperties serverProperties;
|
||||
private final Formatters formatters;
|
||||
private final Graphs graphs;
|
||||
private final Database database;
|
||||
|
||||
public NetworkContainer(
|
||||
ServerContainer bungeeContainer,
|
||||
@ -83,7 +86,7 @@ public class NetworkContainer extends DataContainer {
|
||||
this.config = config;
|
||||
this.locale = locale;
|
||||
this.theme = theme;
|
||||
this.dbSystem = dbSystem;
|
||||
this.database = dbSystem.getDatabase();
|
||||
this.serverProperties = serverProperties;
|
||||
this.formatters = formatters;
|
||||
this.graphs = graphs;
|
||||
@ -97,22 +100,19 @@ public class NetworkContainer extends DataContainer {
|
||||
}
|
||||
|
||||
private void addServerBoxes() {
|
||||
putSupplier(NetworkKeys.NETWORK_PLAYER_ONLINE_DATA, () -> dbSystem.getDatabase().fetch().getPlayersOnlineForServers(
|
||||
putSupplier(NetworkKeys.NETWORK_PLAYER_ONLINE_DATA, () -> database.query(TPSQueries.fetchPlayerOnlineDataOfServers(
|
||||
getValue(NetworkKeys.BUKKIT_SERVERS).orElse(new ArrayList<>()))
|
||||
);
|
||||
putSupplier(NetworkKeys.SERVER_REGISTER_DATA, () -> dbSystem.getDatabase().fetch().getPlayersRegisteredForServers(
|
||||
getValue(NetworkKeys.BUKKIT_SERVERS).orElse(new ArrayList<>()))
|
||||
);
|
||||
));
|
||||
putSupplier(NetworkKeys.SERVERS_TAB, () -> {
|
||||
StringBuilder serverBoxes = new StringBuilder();
|
||||
Map<Integer, List<TPS>> playersOnlineData = getValue(NetworkKeys.NETWORK_PLAYER_ONLINE_DATA).orElse(new HashMap<>());
|
||||
Map<UUID, Integer> registerData = getValue(NetworkKeys.SERVER_REGISTER_DATA).orElse(new HashMap<>());
|
||||
Map<UUID, Integer> userCounts = database.query(ServerAggregateQueries.serverUserCounts());
|
||||
Collection<Server> servers = getValue(NetworkKeys.BUKKIT_SERVERS).orElse(new ArrayList<>());
|
||||
servers.stream()
|
||||
.sorted((one, two) -> String.CASE_INSENSITIVE_ORDER.compare(one.getName(), two.getName()))
|
||||
.forEach(server -> {
|
||||
TPSMutator tpsMutator = new TPSMutator(playersOnlineData.getOrDefault(server.getId(), new ArrayList<>()));
|
||||
int registered = registerData.getOrDefault(server.getUuid(), 0);
|
||||
int registered = userCounts.getOrDefault(server.getUuid(), 0);
|
||||
NetworkServerBox serverBox = new NetworkServerBox(server, registered, tpsMutator, graphs);
|
||||
serverBoxes.append(serverBox.toHtml());
|
||||
});
|
||||
@ -170,7 +170,7 @@ public class NetworkContainer extends DataContainer {
|
||||
private void addPlayerInformation() {
|
||||
putSupplier(NetworkKeys.PLAYERS_TOTAL, () -> getUnsafe(NetworkKeys.PLAYERS_MUTATOR).count());
|
||||
putSupplier(NetworkKeys.WORLD_MAP_SERIES, () ->
|
||||
graphs.special().worldMap(PlayersMutator.forContainer(bungeeContainer)).toHighChartsSeries()
|
||||
graphs.special().worldMap(database.query(ServerAggregateQueries.networkGeolocationCounts())).toHighChartsSeries()
|
||||
);
|
||||
Key<BarGraph> geolocationBarChart = new Key<>(BarGraph.class, "GEOLOCATION_BAR_GRAPH");
|
||||
putSupplier(geolocationBarChart, () -> graphs.bar().geolocationBarGraph(getUnsafe(NetworkKeys.PLAYERS_MUTATOR)));
|
||||
|
@ -16,8 +16,15 @@
|
||||
*/
|
||||
package com.djrapitops.plan.data.store.containers;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.UUID;
|
||||
import com.djrapitops.plan.data.container.Ping;
|
||||
import com.djrapitops.plan.data.container.Session;
|
||||
import com.djrapitops.plan.data.container.UserInfo;
|
||||
import com.djrapitops.plan.data.store.Key;
|
||||
import com.djrapitops.plan.data.store.keys.PerServerKeys;
|
||||
import com.djrapitops.plan.data.store.keys.SessionKeys;
|
||||
import com.djrapitops.plan.data.store.mutators.SessionsMutator;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Container for data about a player linked to a single server.
|
||||
@ -26,4 +33,87 @@ import java.util.UUID;
|
||||
* @see com.djrapitops.plan.data.store.keys.PerServerKeys For Key objects.
|
||||
*/
|
||||
public class PerServerContainer extends HashMap<UUID, DataContainer> {
|
||||
|
||||
public <T> void putToContainerOfServer(UUID serverUUID, Key<T> key, T value) {
|
||||
DataContainer container = getOrDefault(serverUUID, new DynamicDataContainer());
|
||||
container.putRawData(key, value);
|
||||
put(serverUUID, container);
|
||||
}
|
||||
|
||||
public void putUserInfo(UserInfo userInfo) {
|
||||
UUID serverUUID = userInfo.getServerUUID();
|
||||
putToContainerOfServer(serverUUID, PerServerKeys.REGISTERED, userInfo.getRegistered());
|
||||
putToContainerOfServer(serverUUID, PerServerKeys.BANNED, userInfo.isBanned());
|
||||
putToContainerOfServer(serverUUID, PerServerKeys.OPERATOR, userInfo.isOperator());
|
||||
}
|
||||
|
||||
public void putUserInfo(Collection<UserInfo> userInformation) {
|
||||
for (UserInfo userInfo : userInformation) {
|
||||
putUserInfo(userInfo);
|
||||
}
|
||||
}
|
||||
|
||||
public void putCalculatingSuppliers() {
|
||||
for (DataContainer container : values()) {
|
||||
container.putSupplier(PerServerKeys.LAST_SEEN, () -> SessionsMutator.forContainer(container).toLastSeen());
|
||||
|
||||
container.putSupplier(PerServerKeys.WORLD_TIMES, () -> SessionsMutator.forContainer(container).toTotalWorldTimes());
|
||||
container.putSupplier(PerServerKeys.PLAYER_DEATHS, () -> SessionsMutator.forContainer(container).toPlayerDeathList());
|
||||
container.putSupplier(PerServerKeys.PLAYER_KILLS, () -> SessionsMutator.forContainer(container).toPlayerKillList());
|
||||
container.putSupplier(PerServerKeys.PLAYER_KILL_COUNT, () -> container.getUnsafe(PerServerKeys.PLAYER_KILLS).size());
|
||||
container.putSupplier(PerServerKeys.MOB_KILL_COUNT, () -> SessionsMutator.forContainer(container).toMobKillCount());
|
||||
container.putSupplier(PerServerKeys.DEATH_COUNT, () -> SessionsMutator.forContainer(container).toDeathCount());
|
||||
container.putSupplier(PerServerKeys.MOB_DEATH_COUNT, () ->
|
||||
container.getUnsafe(PerServerKeys.DEATH_COUNT) - container.getUnsafe(PerServerKeys.PLAYER_DEATH_COUNT)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public void putSessions(Collection<Session> sessions) {
|
||||
if (sessions == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Session session : sessions) {
|
||||
putSession(session);
|
||||
}
|
||||
}
|
||||
|
||||
private void putSession(Session session) {
|
||||
if (session == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
UUID serverUUID = session.getUnsafe(SessionKeys.SERVER_UUID);
|
||||
DataContainer container = getOrDefault(serverUUID, new DynamicDataContainer());
|
||||
if (!container.supports(PerServerKeys.SESSIONS)) {
|
||||
container.putRawData(PerServerKeys.SESSIONS, new ArrayList<>());
|
||||
}
|
||||
container.getUnsafe(PerServerKeys.SESSIONS).add(session);
|
||||
put(serverUUID, container);
|
||||
}
|
||||
|
||||
public void putPing(List<Ping> pings) {
|
||||
if (pings == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Ping ping : pings) {
|
||||
putPing(ping);
|
||||
}
|
||||
}
|
||||
|
||||
private void putPing(Ping ping) {
|
||||
if (ping == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
UUID serverUUID = ping.getServerUUID();
|
||||
DataContainer container = getOrDefault(serverUUID, new DynamicDataContainer());
|
||||
if (!container.supports(PerServerKeys.PING)) {
|
||||
container.putRawData(PerServerKeys.PING, new ArrayList<>());
|
||||
}
|
||||
container.getUnsafe(PerServerKeys.PING).add(ping);
|
||||
put(serverUUID, container);
|
||||
}
|
||||
}
|
@ -30,7 +30,7 @@ import java.util.Map;
|
||||
* @author Rsl1122
|
||||
* @see com.djrapitops.plan.data.store.keys.PlayerKeys For Key objects.
|
||||
*/
|
||||
public class PlayerContainer extends DataContainer {
|
||||
public class PlayerContainer extends DynamicDataContainer {
|
||||
|
||||
private Map<Long, ActivityIndex> activityIndexCache;
|
||||
|
||||
|
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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.data.store.containers;
|
||||
|
||||
import com.djrapitops.plan.data.store.Key;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* DataContainer that stores everything as raw object value.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class RawDataContainer implements DataContainer {
|
||||
|
||||
private final Map<Key, Object> map;
|
||||
|
||||
/**
|
||||
* Create a RawDataContainer.
|
||||
*/
|
||||
public RawDataContainer() {
|
||||
map = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void putRawData(Key<T> key, T obj) {
|
||||
if (obj == null) {
|
||||
return;
|
||||
}
|
||||
map.put(key, obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void putSupplier(Key<T> key, Supplier<T> supplier) {
|
||||
if (supplier == null) {
|
||||
return;
|
||||
}
|
||||
putRawData(key, supplier.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void putCachingSupplier(Key<T> key, Supplier<T> supplier) {
|
||||
putSupplier(key, supplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> boolean supports(Key<T> key) {
|
||||
return map.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Optional<T> getValue(Key<T> key) {
|
||||
try {
|
||||
return Optional.ofNullable(key.typeCast(map.get(key)));
|
||||
} catch (ClassCastException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getUnsafe(Key<T> key) {
|
||||
Object value = map.get(key);
|
||||
if (value == null) {
|
||||
throw new IllegalArgumentException("Unsupported Key: " + key.getKeyName());
|
||||
}
|
||||
return key.typeCast(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(DataContainer dataContainer) {
|
||||
if (dataContainer instanceof RawDataContainer) {
|
||||
putAll(((RawDataContainer) dataContainer).map);
|
||||
} else {
|
||||
putAll(dataContainer.getMap());
|
||||
}
|
||||
}
|
||||
|
||||
void putAll(Map<Key, Object> map) {
|
||||
this.map.putAll(map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
map.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Key, Object> getMap() {
|
||||
return map;
|
||||
}
|
||||
}
|
@ -22,5 +22,5 @@ package com.djrapitops.plan.data.store.containers;
|
||||
* @author Rsl1122
|
||||
* @see com.djrapitops.plan.data.store.keys.ServerKeys For Key objects.
|
||||
*/
|
||||
public class ServerContainer extends DataContainer {
|
||||
public class ServerContainer extends DynamicDataContainer {
|
||||
}
|
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* 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.data.store.containers;
|
||||
|
||||
import com.djrapitops.plan.data.store.CachingSupplier;
|
||||
import com.djrapitops.plan.data.store.Key;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* DataContainer implementation that stores everything in {@link Supplier} objects.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class SupplierDataContainer implements DataContainer {
|
||||
|
||||
private final Map<Key, Supplier> map;
|
||||
private long timeToLive;
|
||||
|
||||
/**
|
||||
* Create a SupplierDataContainer with a default TTL of 30 seconds.
|
||||
*/
|
||||
public SupplierDataContainer() {
|
||||
this(TimeUnit.SECONDS.toMillis(30L));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a SupplierDataContainer with a custom TTL.
|
||||
* <p>
|
||||
* The old value is not removed from memory until the supplier is called again.
|
||||
*
|
||||
* @param timeToLive TTL that determines how long a CachingSupplier value is deemed valid.
|
||||
*/
|
||||
public SupplierDataContainer(long timeToLive) {
|
||||
this.timeToLive = timeToLive;
|
||||
map = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void putRawData(Key<T> key, T obj) {
|
||||
putSupplier(key, () -> obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void putSupplier(Key<T> key, Supplier<T> supplier) {
|
||||
if (supplier == null) {
|
||||
return;
|
||||
}
|
||||
map.put(key, supplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void putCachingSupplier(Key<T> key, Supplier<T> supplier) {
|
||||
if (supplier == null) {
|
||||
return;
|
||||
}
|
||||
map.put(key, new CachingSupplier<>(supplier, timeToLive));
|
||||
}
|
||||
|
||||
private <T> Supplier<T> getSupplier(Key<T> key) {
|
||||
return (Supplier<T>) map.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> boolean supports(Key<T> key) {
|
||||
return map.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Optional<T> getValue(Key<T> key) {
|
||||
Supplier<T> supplier = getSupplier(key);
|
||||
if (supplier == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
try {
|
||||
return Optional.ofNullable(supplier.get());
|
||||
} catch (ClassCastException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getUnsafe(Key<T> key) {
|
||||
Supplier supplier = map.get(key);
|
||||
if (supplier == null) {
|
||||
throw new IllegalArgumentException("Unsupported Key: " + key.getKeyName());
|
||||
}
|
||||
return key.typeCast(supplier.get());
|
||||
}
|
||||
|
||||
private void putAll(Map<Key, Supplier> toPut) {
|
||||
map.putAll(toPut);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(DataContainer dataContainer) {
|
||||
if (dataContainer instanceof SupplierDataContainer) {
|
||||
putAll(((SupplierDataContainer) dataContainer).map);
|
||||
} else {
|
||||
for (Map.Entry<Key, Object> entry : dataContainer.getMap().entrySet()) {
|
||||
putRawData(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
map.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Key, Object> getMap() {
|
||||
return map.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().get()));
|
||||
}
|
||||
}
|
@ -54,7 +54,9 @@ public class CommonKeys {
|
||||
public static final Key<List<PlayerDeath>> PLAYER_DEATHS = new Key<>(new Type<List<PlayerDeath>>() {}, "player_deaths");
|
||||
public static final Key<List<PlayerKill>> PLAYER_KILLS = new Key<>(new Type<List<PlayerKill>>() {}, "player_kills");
|
||||
public static final Key<Integer> PLAYER_KILL_COUNT = new Key<>(Integer.class, "player_kill_count");
|
||||
public static final Key<Integer> PLAYER_DEATH_COUNT = new Key<>(Integer.class, "player_death_count");
|
||||
public static final Key<Integer> MOB_KILL_COUNT = new Key<>(Integer.class, "mob_kill_count");
|
||||
public static final Key<Integer> MOB_DEATH_COUNT = new Key<>(Integer.class, "mob_death_count");
|
||||
public static final Key<Integer> DEATH_COUNT = new Key<>(Integer.class, "death_count");
|
||||
|
||||
public static final Key<Boolean> BANNED = new Key<>(Boolean.class, "banned");
|
||||
|
@ -74,6 +74,7 @@ public class NetworkKeys {
|
||||
public static final Key<Collection<Server>> BUKKIT_SERVERS = new Key<>(new Type<Collection<Server>>() {}, "BUKKIT_SERVERS");
|
||||
public static final Key<TreeMap<Long, Map<String, Set<UUID>>>> ACTIVITY_DATA = CommonKeys.ACTIVITY_DATA;
|
||||
public static final Key<Map<Integer, List<TPS>>> NETWORK_PLAYER_ONLINE_DATA = new Key<>(new Type<Map<Integer, List<TPS>>>() {}, "NETWORK_PLAYER_ONLINE_DATA");
|
||||
@Deprecated
|
||||
public static final Key<Map<UUID, Integer>> SERVER_REGISTER_DATA = new Key<>(new Type<Map<UUID, Integer>>() {}, "SERVER_REGISTER_DATA");
|
||||
|
||||
private NetworkKeys() {
|
||||
|
@ -30,7 +30,7 @@ import java.util.List;
|
||||
* Key objects for PerServerContainer container.
|
||||
*
|
||||
* @author Rsl1122
|
||||
* @see com.djrapitops.plan.system.database.databases.sql.operation.SQLFetchOps For Suppliers for each key
|
||||
* @see com.djrapitops.plan.db.access.queries.containers.PerServerContainerQuery For Suppliers for each key
|
||||
* @see PerServerContainer For the DataContainer.
|
||||
*/
|
||||
public class PerServerKeys {
|
||||
@ -45,10 +45,14 @@ public class PerServerKeys {
|
||||
public static final Key<List<Session>> SESSIONS = CommonKeys.SESSIONS;
|
||||
public static final Key<WorldTimes> WORLD_TIMES = CommonKeys.WORLD_TIMES;
|
||||
|
||||
@Deprecated
|
||||
public static final Key<List<PlayerKill>> PLAYER_KILLS = CommonKeys.PLAYER_KILLS;
|
||||
@Deprecated
|
||||
public static final Key<List<PlayerDeath>> PLAYER_DEATHS = CommonKeys.PLAYER_DEATHS;
|
||||
public static final Key<Integer> PLAYER_KILL_COUNT = CommonKeys.PLAYER_KILL_COUNT;
|
||||
public static final Key<Integer> PLAYER_DEATH_COUNT = CommonKeys.PLAYER_DEATH_COUNT;
|
||||
public static final Key<Integer> MOB_KILL_COUNT = CommonKeys.MOB_KILL_COUNT;
|
||||
public static final Key<Integer> MOB_DEATH_COUNT = CommonKeys.MOB_DEATH_COUNT;
|
||||
public static final Key<Integer> DEATH_COUNT = CommonKeys.DEATH_COUNT;
|
||||
public static final Key<Long> LAST_SEEN = CommonKeys.LAST_SEEN;
|
||||
|
||||
|
@ -46,6 +46,7 @@ public class SessionKeys {
|
||||
public static final Key<Integer> PLAYER_KILL_COUNT = CommonKeys.PLAYER_KILL_COUNT;
|
||||
public static final Key<Integer> MOB_KILL_COUNT = CommonKeys.MOB_KILL_COUNT;
|
||||
public static final Key<Integer> DEATH_COUNT = CommonKeys.DEATH_COUNT;
|
||||
@Deprecated
|
||||
public static final Key<List<PlayerDeath>> PLAYER_DEATHS = CommonKeys.PLAYER_DEATHS;
|
||||
|
||||
@Deprecated
|
||||
|
@ -44,10 +44,6 @@ public class SessionsMutator {
|
||||
return new SessionsMutator(container.getValue(CommonKeys.SESSIONS).orElse(new ArrayList<>()));
|
||||
}
|
||||
|
||||
public static SessionsMutator copyOf(SessionsMutator mutator) {
|
||||
return new SessionsMutator(new ArrayList<>(mutator.sessions));
|
||||
}
|
||||
|
||||
public SessionsMutator(List<Session> sessions) {
|
||||
this.sessions = sessions;
|
||||
}
|
||||
@ -208,6 +204,28 @@ public class SessionsMutator {
|
||||
};
|
||||
}
|
||||
|
||||
public static Map<UUID, List<Session>> sortByPlayers(List<Session> sessions) {
|
||||
Map<UUID, List<Session>> sorted = new HashMap<>();
|
||||
for (Session session : sessions) {
|
||||
UUID playerUUID = session.getUnsafe(SessionKeys.UUID);
|
||||
List<Session> playerSessions = sorted.getOrDefault(playerUUID, new ArrayList<>());
|
||||
playerSessions.add(session);
|
||||
sorted.put(playerUUID, playerSessions);
|
||||
}
|
||||
return sorted;
|
||||
}
|
||||
|
||||
public static Map<UUID, List<Session>> sortByServers(List<Session> sessions) {
|
||||
Map<UUID, List<Session>> sorted = new HashMap<>();
|
||||
for (Session session : sessions) {
|
||||
UUID serverUUID = session.getUnsafe(SessionKeys.SERVER_UUID);
|
||||
List<Session> serverSessions = sorted.getOrDefault(serverUUID, new ArrayList<>());
|
||||
serverSessions.add(session);
|
||||
sorted.put(serverUUID, serverSessions);
|
||||
}
|
||||
return sorted;
|
||||
}
|
||||
|
||||
public int toPlayerDeathCount() {
|
||||
return toPlayerDeathList().size();
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ package com.djrapitops.plan.data.store.mutators.health;
|
||||
import com.djrapitops.plan.data.store.Key;
|
||||
import com.djrapitops.plan.data.store.containers.DataContainer;
|
||||
import com.djrapitops.plan.data.store.containers.NetworkContainer;
|
||||
import com.djrapitops.plan.data.store.containers.SupplierDataContainer;
|
||||
import com.djrapitops.plan.data.store.keys.AnalysisKeys;
|
||||
import com.djrapitops.plan.data.store.keys.NetworkKeys;
|
||||
import com.djrapitops.plan.data.store.mutators.PlayersMutator;
|
||||
@ -146,7 +147,7 @@ public class NetworkHealthInformation extends AbstractHealthInfo {
|
||||
|
||||
for (Server server : servers) {
|
||||
UUID serverUUID = server.getUuid();
|
||||
DataContainer serverContainer = new DataContainer();
|
||||
DataContainer serverContainer = new SupplierDataContainer();
|
||||
serverContainer.putRawData(serverKey, server);
|
||||
|
||||
PlayersMutator serverPlayers = playersMutator.filterPlayedOnServer(serverUUID);
|
||||
|
@ -77,6 +77,8 @@ public class WorldTimes {
|
||||
* @param changeTime Epoch ms the change occurred.
|
||||
*/
|
||||
public void updateState(String worldName, String gameMode, long changeTime) {
|
||||
if (worldName == null || gameMode == null) return;
|
||||
|
||||
GMTimes currentGMTimes = times.get(currentWorld);
|
||||
if (currentWorld.equals(worldName)) {
|
||||
currentGMTimes.changeState(gameMode, changeTime);
|
||||
@ -182,4 +184,7 @@ public class WorldTimes {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean contains(String worldName) {
|
||||
return times.containsKey(worldName);
|
||||
}
|
||||
}
|
||||
|
@ -14,31 +14,32 @@
|
||||
* 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.system.processing.processors.player;
|
||||
|
||||
import com.djrapitops.plan.system.database.databases.Database;
|
||||
import com.djrapitops.plan.system.processing.CriticalRunnable;
|
||||
|
||||
import java.util.UUID;
|
||||
package com.djrapitops.plan.db;
|
||||
|
||||
/**
|
||||
* Updates the Kick count of a user.
|
||||
* Abstract class representing a Database.
|
||||
* <p>
|
||||
* All Operations methods should be only called from an asynchronous thread.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class KickProcessor implements CriticalRunnable {
|
||||
public abstract class AbstractDatabase implements Database {
|
||||
|
||||
private final UUID uuid;
|
||||
protected DBAccessLock accessLock;
|
||||
private State state;
|
||||
|
||||
private final Database database;
|
||||
|
||||
KickProcessor(UUID uuid, Database database) {
|
||||
this.uuid = uuid;
|
||||
this.database = database;
|
||||
public AbstractDatabase() {
|
||||
state = State.CLOSED;
|
||||
accessLock = new DBAccessLock(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
database.save().playerWasKicked(uuid);
|
||||
public State getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(State state) {
|
||||
this.state = state;
|
||||
accessLock.operabilityChanged();
|
||||
}
|
||||
}
|
@ -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.db;
|
||||
|
||||
import com.djrapitops.plan.api.exceptions.database.DBOpException;
|
||||
import com.djrapitops.plan.db.access.transactions.Transaction;
|
||||
import com.djrapitops.plan.db.access.transactions.init.OperationCriticalTransaction;
|
||||
|
||||
/**
|
||||
* Database Lock that prevents queries and transactions from taking place before database schema is ready.
|
||||
* <p>
|
||||
* - OperationCriticalTransactions pass through the Access lock without blocking to allow the initial transactions.
|
||||
* - Queries inside Transactions skip access log to allow OperationCriticalTransactions perform queries.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class DBAccessLock {
|
||||
|
||||
private final Database database;
|
||||
|
||||
private final Object lockObject;
|
||||
|
||||
public DBAccessLock(Database database) {
|
||||
this.database = database;
|
||||
this.lockObject = new Object();
|
||||
}
|
||||
|
||||
public void checkAccess() {
|
||||
checkAccess(false);
|
||||
}
|
||||
|
||||
public void checkAccess(Transaction transaction) {
|
||||
checkAccess(transaction instanceof OperationCriticalTransaction);
|
||||
}
|
||||
|
||||
private void checkAccess(boolean isOperationCriticalTransaction) {
|
||||
if (isOperationCriticalTransaction) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
while (database.getState() != Database.State.OPEN) {
|
||||
synchronized (lockObject) {
|
||||
lockObject.wait();
|
||||
if (database.getState() == Database.State.CLOSED) {
|
||||
throw new DBOpException("Database failed to open, Query has failed. (This exception is necessary to not keep query threads waiting)");
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
public void operabilityChanged() {
|
||||
synchronized (lockObject) {
|
||||
lockObject.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
@ -14,7 +14,7 @@
|
||||
* 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.system.database.databases;
|
||||
package com.djrapitops.plan.db;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@ -58,10 +58,10 @@ public enum DBType {
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to check if the {@code DBType} supports <b>most</b> MySQL Queries.<p>
|
||||
* Used to check if the {@code DBType} supports <b>most</b> MySQL MySQLSchemaQueries.<p>
|
||||
* When specific Statements are not compatible, the {@code DBType} should be checked.
|
||||
*
|
||||
* @return if the database supports MySQL Queries
|
||||
* @return if the database supports MySQL MySQLSchemaQueries
|
||||
*/
|
||||
public boolean supportsMySQLQueries() {
|
||||
return supportingMySQLQueries;
|
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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.db;
|
||||
|
||||
import com.djrapitops.plan.api.exceptions.database.DBInitException;
|
||||
import com.djrapitops.plan.db.access.Query;
|
||||
import com.djrapitops.plan.db.access.transactions.Transaction;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
* Interface for interacting with a Plan SQL database.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public interface Database {
|
||||
|
||||
/**
|
||||
* Initializes the Database.
|
||||
* <p>
|
||||
* Queries can be performed after this request has completed all required transactions for the database operations.
|
||||
*
|
||||
* @throws DBInitException if Database fails to initiate.
|
||||
*/
|
||||
void init();
|
||||
|
||||
void close();
|
||||
|
||||
/**
|
||||
* Execute an SQL Query statement to get a result.
|
||||
* <p>
|
||||
* This method should only be called from an asynchronous thread.
|
||||
*
|
||||
* @param query QueryStatement to execute.
|
||||
* @param <T> Type of the object to be returned.
|
||||
* @return Result of the query.
|
||||
*/
|
||||
<T> T query(Query<T> query);
|
||||
|
||||
/**
|
||||
* Execute an SQL Transaction.
|
||||
*
|
||||
* @param transaction Transaction to execute.
|
||||
* @return Future that is finished when the transaction has been executed.
|
||||
*/
|
||||
Future<?> executeTransaction(Transaction transaction);
|
||||
|
||||
/**
|
||||
* Used to get the {@code DBType} of the Database
|
||||
*
|
||||
* @return the {@code DBType}
|
||||
* @see DBType
|
||||
*/
|
||||
DBType getType();
|
||||
|
||||
State getState();
|
||||
|
||||
enum State {
|
||||
CLOSED,
|
||||
PATCHING,
|
||||
OPEN
|
||||
}
|
||||
}
|
@ -14,19 +14,18 @@
|
||||
* 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.system.database.databases.sql;
|
||||
package com.djrapitops.plan.db;
|
||||
|
||||
import com.djrapitops.plan.api.exceptions.database.DBInitException;
|
||||
import com.djrapitops.plan.data.store.containers.NetworkContainer;
|
||||
import com.djrapitops.plan.system.database.databases.DBType;
|
||||
import com.djrapitops.plan.db.tasks.KeepAliveTask;
|
||||
import com.djrapitops.plan.system.file.PlanFiles;
|
||||
import com.djrapitops.plan.system.info.server.ServerInfo;
|
||||
import com.djrapitops.plan.system.locale.Locale;
|
||||
import com.djrapitops.plan.system.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.system.settings.paths.DatabaseSettings;
|
||||
import com.djrapitops.plan.utilities.MiscUtils;
|
||||
import com.djrapitops.plugin.benchmarking.Timings;
|
||||
import com.djrapitops.plugin.logging.L;
|
||||
import com.djrapitops.plan.utilities.java.ThrowableUtils;
|
||||
import com.djrapitops.plugin.logging.console.PluginLogger;
|
||||
import com.djrapitops.plugin.logging.error.ErrorHandler;
|
||||
import com.djrapitops.plugin.task.PluginTask;
|
||||
@ -61,23 +60,21 @@ public class H2DB extends SQLDB {
|
||||
NetworkContainer.Factory networkContainerFactory,
|
||||
RunnableFactory runnableFactory,
|
||||
PluginLogger logger,
|
||||
Timings timings,
|
||||
ErrorHandler errorHandler
|
||||
) {
|
||||
super(() -> serverInfo.get().getServerUUID(), locale, config, networkContainerFactory, runnableFactory, logger, timings, errorHandler);
|
||||
super(() -> serverInfo.get().getServerUUID(), locale, config, networkContainerFactory, runnableFactory, logger, errorHandler);
|
||||
dbName = databaseFile.getName();
|
||||
this.databaseFile = databaseFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupDataSource() throws DBInitException {
|
||||
public void setupDataSource() {
|
||||
try {
|
||||
connection = getNewConnection(databaseFile);
|
||||
} catch (SQLException e) {
|
||||
throw new DBInitException(e);
|
||||
throw new DBInitException(e.getMessage(), e);
|
||||
}
|
||||
|
||||
execute("SET REFERENTIAL_INTEGRITY FALSE");
|
||||
startConnectionPingTask();
|
||||
}
|
||||
|
||||
@ -145,22 +142,12 @@ public class H2DB extends SQLDB {
|
||||
stopConnectionPingTask();
|
||||
|
||||
if (connection != null) {
|
||||
logger.debug("H2DB " + dbName + ": Closed Connection");
|
||||
logger.debug("H2 Connection close prompted by: " + ThrowableUtils.findCallerAfterClass(Thread.currentThread().getStackTrace(), H2DB.class));
|
||||
logger.debug("H2 " + dbName + ": Closed Connection");
|
||||
MiscUtils.close(connection);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void commit(Connection connection) {
|
||||
try {
|
||||
connection.commit();
|
||||
} catch (SQLException e) {
|
||||
if (!e.getMessage().contains("cannot commit")) {
|
||||
errorHandler.log(L.ERROR, this.getClass(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void returnToPool(Connection connection) {
|
||||
// Connection pool not in use, no action required.
|
||||
@ -189,7 +176,6 @@ public class H2DB extends SQLDB {
|
||||
private final NetworkContainer.Factory networkContainerFactory;
|
||||
private final RunnableFactory runnableFactory;
|
||||
private final PluginLogger logger;
|
||||
private final Timings timings;
|
||||
private final ErrorHandler errorHandler;
|
||||
private PlanFiles files;
|
||||
|
||||
@ -202,7 +188,6 @@ public class H2DB extends SQLDB {
|
||||
NetworkContainer.Factory networkContainerFactory,
|
||||
RunnableFactory runnableFactory,
|
||||
PluginLogger logger,
|
||||
Timings timings,
|
||||
ErrorHandler errorHandler
|
||||
) {
|
||||
this.locale = locale;
|
||||
@ -212,7 +197,6 @@ public class H2DB extends SQLDB {
|
||||
this.networkContainerFactory = networkContainerFactory;
|
||||
this.runnableFactory = runnableFactory;
|
||||
this.logger = logger;
|
||||
this.timings = timings;
|
||||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
@ -228,7 +212,7 @@ public class H2DB extends SQLDB {
|
||||
return new H2DB(databaseFile,
|
||||
locale, config, serverInfo,
|
||||
networkContainerFactory,
|
||||
runnableFactory, logger, timings, errorHandler
|
||||
runnableFactory, logger, errorHandler
|
||||
);
|
||||
}
|
||||
|
@ -14,12 +14,11 @@
|
||||
* 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.system.database.databases.sql;
|
||||
package com.djrapitops.plan.db;
|
||||
|
||||
import com.djrapitops.plan.api.exceptions.database.DBInitException;
|
||||
import com.djrapitops.plan.api.exceptions.database.DBOpException;
|
||||
import com.djrapitops.plan.data.store.containers.NetworkContainer;
|
||||
import com.djrapitops.plan.system.database.databases.DBType;
|
||||
import com.djrapitops.plan.system.info.server.ServerInfo;
|
||||
import com.djrapitops.plan.system.locale.Locale;
|
||||
import com.djrapitops.plan.system.locale.lang.PluginLang;
|
||||
@ -64,7 +63,7 @@ public class MySQLDB extends SQLDB {
|
||||
Timings timings,
|
||||
ErrorHandler errorHandler
|
||||
) {
|
||||
super(() -> serverInfo.get().getServerUUID(), locale, config, networkContainerFactory, runnableFactory, pluginLogger, timings, errorHandler);
|
||||
super(() -> serverInfo.get().getServerUUID(), locale, config, networkContainerFactory, runnableFactory, pluginLogger, errorHandler);
|
||||
}
|
||||
|
||||
private static synchronized void increment() {
|
||||
@ -80,7 +79,7 @@ public class MySQLDB extends SQLDB {
|
||||
* Setups the {@link HikariDataSource}
|
||||
*/
|
||||
@Override
|
||||
public void setupDataSource() throws DBInitException {
|
||||
public void setupDataSource() {
|
||||
try {
|
||||
HikariConfig hikariConfig = new HikariConfig();
|
||||
|
||||
@ -88,7 +87,8 @@ public class MySQLDB extends SQLDB {
|
||||
String port = config.get(DatabaseSettings.MYSQL_PORT);
|
||||
String database = config.get(DatabaseSettings.MYSQL_DATABASE);
|
||||
String launchOptions = config.get(DatabaseSettings.MYSQL_LAUNCH_OPTIONS);
|
||||
if (launchOptions.isEmpty() || !launchOptions.startsWith("?") || launchOptions.endsWith("&")) {
|
||||
// REGEX: match "?", match "word=word&" *-times, match "word=word"
|
||||
if (launchOptions.isEmpty() || !launchOptions.matches("\\?((\\w*=\\w*)&)*(\\w*=\\w*)")) {
|
||||
launchOptions = "?rewriteBatchedStatements=true&useSSL=false";
|
||||
logger.error(locale.getString(PluginLang.DB_MYSQL_LAUNCH_OPTIONS_FAIL, launchOptions));
|
||||
}
|
||||
@ -109,9 +109,7 @@ public class MySQLDB extends SQLDB {
|
||||
hikariConfig.setLeakDetectionThreshold(TimeUnit.MINUTES.toMillis(10L));
|
||||
|
||||
this.dataSource = new HikariDataSource(hikariConfig);
|
||||
|
||||
getConnection();
|
||||
} catch (HikariPool.PoolInitializationException | SQLException e) {
|
||||
} catch (HikariPool.PoolInitializationException e) {
|
||||
throw new DBInitException("Failed to set-up HikariCP Datasource: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
@ -127,11 +125,12 @@ public class MySQLDB extends SQLDB {
|
||||
try {
|
||||
setupDataSource();
|
||||
// get new connection after restarting pool
|
||||
return dataSource.getConnection();
|
||||
connection = dataSource.getConnection();
|
||||
} catch (DBInitException e) {
|
||||
throw new DBOpException("Failed to restart DataSource after a connection was invalid: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
if (connection.getAutoCommit()) connection.setAutoCommit(false);
|
||||
return connection;
|
||||
}
|
||||
|
||||
@ -155,11 +154,6 @@ public class MySQLDB extends SQLDB {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void commit(Connection connection) {
|
||||
returnToPool(connection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
273
Plan/common/src/main/java/com/djrapitops/plan/db/SQLDB.java
Normal file
273
Plan/common/src/main/java/com/djrapitops/plan/db/SQLDB.java
Normal file
@ -0,0 +1,273 @@
|
||||
/*
|
||||
* 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.db;
|
||||
|
||||
import com.djrapitops.plan.api.exceptions.database.DBInitException;
|
||||
import com.djrapitops.plan.api.exceptions.database.DBOpException;
|
||||
import com.djrapitops.plan.api.exceptions.database.FatalDBException;
|
||||
import com.djrapitops.plan.data.store.containers.NetworkContainer;
|
||||
import com.djrapitops.plan.db.access.Query;
|
||||
import com.djrapitops.plan.db.access.transactions.Transaction;
|
||||
import com.djrapitops.plan.db.access.transactions.init.CreateIndexTransaction;
|
||||
import com.djrapitops.plan.db.access.transactions.init.CreateTablesTransaction;
|
||||
import com.djrapitops.plan.db.access.transactions.init.OperationCriticalTransaction;
|
||||
import com.djrapitops.plan.db.patches.*;
|
||||
import com.djrapitops.plan.system.locale.Locale;
|
||||
import com.djrapitops.plan.system.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.system.settings.paths.TimeSettings;
|
||||
import com.djrapitops.plan.utilities.java.ThrowableUtils;
|
||||
import com.djrapitops.plugin.api.TimeAmount;
|
||||
import com.djrapitops.plugin.logging.L;
|
||||
import com.djrapitops.plugin.logging.console.PluginLogger;
|
||||
import com.djrapitops.plugin.logging.error.ErrorHandler;
|
||||
import com.djrapitops.plugin.task.AbsRunnable;
|
||||
import com.djrapitops.plugin.task.RunnableFactory;
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Class containing main logic for different data related save and load functionality.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public abstract class SQLDB extends AbstractDatabase {
|
||||
|
||||
private final Supplier<UUID> serverUUIDSupplier;
|
||||
|
||||
protected final Locale locale;
|
||||
protected final PlanConfig config;
|
||||
protected final NetworkContainer.Factory networkContainerFactory;
|
||||
protected final RunnableFactory runnableFactory;
|
||||
protected final PluginLogger logger;
|
||||
protected final ErrorHandler errorHandler;
|
||||
|
||||
private Supplier<ExecutorService> transactionExecutorServiceProvider;
|
||||
private ExecutorService transactionExecutor;
|
||||
|
||||
public SQLDB(
|
||||
Supplier<UUID> serverUUIDSupplier,
|
||||
Locale locale,
|
||||
PlanConfig config,
|
||||
NetworkContainer.Factory networkContainerFactory, RunnableFactory runnableFactory,
|
||||
PluginLogger logger,
|
||||
ErrorHandler errorHandler
|
||||
) {
|
||||
this.serverUUIDSupplier = serverUUIDSupplier;
|
||||
this.locale = locale;
|
||||
this.config = config;
|
||||
this.networkContainerFactory = networkContainerFactory;
|
||||
this.runnableFactory = runnableFactory;
|
||||
this.logger = logger;
|
||||
this.errorHandler = errorHandler;
|
||||
|
||||
this.transactionExecutorServiceProvider = () -> Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat("Plan " + getClass().getSimpleName() + "-transaction-thread-%d").build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
List<Runnable> unfinishedTransactions = closeTransactionExecutor(transactionExecutor);
|
||||
this.transactionExecutor = transactionExecutorServiceProvider.get();
|
||||
|
||||
setState(State.PATCHING);
|
||||
|
||||
setupDataSource();
|
||||
setupDatabase();
|
||||
|
||||
for (Runnable unfinishedTransaction : unfinishedTransactions) {
|
||||
transactionExecutor.submit(unfinishedTransaction);
|
||||
}
|
||||
|
||||
// If an OperationCriticalTransaction fails open is set to false.
|
||||
// See executeTransaction method below.
|
||||
if (getState() == State.CLOSED) {
|
||||
throw new DBInitException("Failed to set-up Database");
|
||||
}
|
||||
}
|
||||
|
||||
private List<Runnable> closeTransactionExecutor(ExecutorService transactionExecutor) {
|
||||
if (transactionExecutor == null || transactionExecutor.isShutdown() || transactionExecutor.isTerminated()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
transactionExecutor.shutdown();
|
||||
try {
|
||||
Long waitMs = config.getOrDefault(TimeSettings.DB_TRANSACTION_FINISH_WAIT_DELAY, TimeUnit.SECONDS.toMillis(20L));
|
||||
if (!transactionExecutor.awaitTermination(waitMs, TimeUnit.MILLISECONDS)) {
|
||||
List<Runnable> unfinished = transactionExecutor.shutdownNow();
|
||||
int unfinishedCount = unfinished.size();
|
||||
if (unfinishedCount > 0) {
|
||||
logger.warn(unfinishedCount + " unfinished database transactions were not executed.");
|
||||
}
|
||||
return unfinished;
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
Patch[] patches() {
|
||||
return new Patch[]{
|
||||
new Version10Patch(),
|
||||
new GeoInfoLastUsedPatch(),
|
||||
new SessionAFKTimePatch(),
|
||||
new KillsServerIDPatch(),
|
||||
new WorldTimesSeverIDPatch(),
|
||||
new WorldsServerIDPatch(),
|
||||
new NicknameLastSeenPatch(),
|
||||
new VersionTableRemovalPatch(),
|
||||
new DiskUsagePatch(),
|
||||
new WorldsOptimizationPatch(),
|
||||
new WorldTimesOptimizationPatch(),
|
||||
new KillsOptimizationPatch(),
|
||||
new SessionsOptimizationPatch(),
|
||||
new PingOptimizationPatch(),
|
||||
new NicknamesOptimizationPatch(),
|
||||
new UserInfoOptimizationPatch(),
|
||||
new GeoInfoOptimizationPatch(),
|
||||
new TransferTableRemovalPatch(),
|
||||
new IPHashPatch(),
|
||||
new IPAnonPatch(),
|
||||
new BadAFKThresholdValuePatch()
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures connection functions correctly and all tables exist.
|
||||
* <p>
|
||||
* Updates to latest schema.
|
||||
*/
|
||||
private void setupDatabase() {
|
||||
executeTransaction(new CreateTablesTransaction());
|
||||
for (Patch patch : patches()) {
|
||||
executeTransaction(patch);
|
||||
}
|
||||
executeTransaction(new OperationCriticalTransaction() {
|
||||
@Override
|
||||
protected void performOperations() {
|
||||
if (getState() == State.PATCHING) setState(State.OPEN);
|
||||
}
|
||||
});
|
||||
registerIndexCreationTask();
|
||||
}
|
||||
|
||||
private void registerIndexCreationTask() {
|
||||
try {
|
||||
runnableFactory.create("Database Index Creation", new AbsRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
executeTransaction(new CreateIndexTransaction());
|
||||
}
|
||||
}).runTaskLaterAsynchronously(TimeAmount.toTicks(1, TimeUnit.MINUTES));
|
||||
} catch (Exception ignore) {
|
||||
// Task failed to register because plugin is being disabled
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up the source for connections.
|
||||
*
|
||||
* @throws DBInitException If the DataSource fails to be initialized.
|
||||
*/
|
||||
public abstract void setupDataSource();
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
setState(State.CLOSED);
|
||||
closeTransactionExecutor(transactionExecutor);
|
||||
}
|
||||
|
||||
public abstract Connection getConnection() throws SQLException;
|
||||
|
||||
public abstract void returnToPool(Connection connection);
|
||||
|
||||
@Override
|
||||
public <T> T query(Query<T> query) {
|
||||
accessLock.checkAccess();
|
||||
return query.executeQuery(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<?> executeTransaction(Transaction transaction) {
|
||||
if (getState() == State.CLOSED) {
|
||||
throw new DBOpException("Transaction tried to execute although database is closed.");
|
||||
}
|
||||
|
||||
Exception origin = new Exception();
|
||||
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
accessLock.checkAccess(transaction);
|
||||
transaction.executeTransaction(this);
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}, getTransactionExecutor()).handle(errorHandler(origin));
|
||||
}
|
||||
|
||||
private BiFunction<CompletableFuture<Object>, Throwable, CompletableFuture<Object>> errorHandler(Exception origin) {
|
||||
return (obj, throwable) -> {
|
||||
if (throwable == null) {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
if (throwable instanceof FatalDBException) {
|
||||
setState(State.CLOSED);
|
||||
}
|
||||
ThrowableUtils.appendEntryPointToCause(throwable, origin);
|
||||
|
||||
errorHandler.log(L.ERROR, getClass(), throwable);
|
||||
return CompletableFuture.completedFuture(null);
|
||||
};
|
||||
}
|
||||
|
||||
private ExecutorService getTransactionExecutor() {
|
||||
if (transactionExecutor == null) {
|
||||
transactionExecutor = transactionExecutorServiceProvider.get();
|
||||
}
|
||||
return transactionExecutor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
SQLDB sqldb = (SQLDB) o;
|
||||
return getType() == sqldb.getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(getType().getName());
|
||||
}
|
||||
|
||||
public Supplier<UUID> getServerUUIDSupplier() {
|
||||
return serverUUIDSupplier;
|
||||
}
|
||||
|
||||
public NetworkContainer.Factory getNetworkContainerFactory() {
|
||||
return networkContainerFactory;
|
||||
}
|
||||
|
||||
public void setTransactionExecutorServiceProvider(Supplier<ExecutorService> transactionExecutorServiceProvider) {
|
||||
this.transactionExecutorServiceProvider = transactionExecutorServiceProvider;
|
||||
}
|
||||
}
|
@ -14,18 +14,18 @@
|
||||
* 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.system.database.databases.sql;
|
||||
package com.djrapitops.plan.db;
|
||||
|
||||
import com.djrapitops.plan.api.exceptions.database.DBInitException;
|
||||
import com.djrapitops.plan.data.store.containers.NetworkContainer;
|
||||
import com.djrapitops.plan.system.database.databases.DBType;
|
||||
import com.djrapitops.plan.db.tasks.KeepAliveTask;
|
||||
import com.djrapitops.plan.system.file.PlanFiles;
|
||||
import com.djrapitops.plan.system.info.server.ServerInfo;
|
||||
import com.djrapitops.plan.system.locale.Locale;
|
||||
import com.djrapitops.plan.system.locale.lang.PluginLang;
|
||||
import com.djrapitops.plan.system.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.utilities.MiscUtils;
|
||||
import com.djrapitops.plugin.benchmarking.Timings;
|
||||
import com.djrapitops.plan.utilities.java.ThrowableUtils;
|
||||
import com.djrapitops.plugin.logging.L;
|
||||
import com.djrapitops.plugin.logging.console.PluginLogger;
|
||||
import com.djrapitops.plugin.logging.error.ErrorHandler;
|
||||
@ -59,20 +59,21 @@ public class SQLiteDB extends SQLDB {
|
||||
NetworkContainer.Factory networkContainerFactory,
|
||||
RunnableFactory runnableFactory,
|
||||
PluginLogger logger,
|
||||
Timings timings,
|
||||
ErrorHandler errorHandler
|
||||
) {
|
||||
super(() -> serverInfo.get().getServerUUID(), locale, config, networkContainerFactory, runnableFactory, logger, timings, errorHandler);
|
||||
super(() -> serverInfo.get().getServerUUID(), locale, config, networkContainerFactory, runnableFactory, logger, errorHandler);
|
||||
dbName = databaseFile.getName();
|
||||
this.databaseFile = databaseFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupDataSource() throws DBInitException {
|
||||
public void setupDataSource() {
|
||||
try {
|
||||
if (connection != null) connection.close();
|
||||
|
||||
connection = getNewConnection(databaseFile);
|
||||
} catch (SQLException e) {
|
||||
throw new DBInitException(e);
|
||||
throw new DBInitException(e.getMessage(), e);
|
||||
}
|
||||
startConnectionPingTask();
|
||||
}
|
||||
@ -140,6 +141,8 @@ public class SQLiteDB extends SQLDB {
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
logger.debug("SQLite Connection close prompted by: " + ThrowableUtils.findCallerAfterClass(Thread.currentThread().getStackTrace(), SQLiteDB.class));
|
||||
|
||||
super.close();
|
||||
stopConnectionPingTask();
|
||||
|
||||
@ -149,17 +152,6 @@ public class SQLiteDB extends SQLDB {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void commit(Connection connection) {
|
||||
try {
|
||||
connection.commit();
|
||||
} catch (SQLException e) {
|
||||
if (!e.getMessage().contains("cannot commit")) {
|
||||
errorHandler.log(L.ERROR, this.getClass(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void returnToPool(Connection connection) {
|
||||
// Connection pool not in use, no action required.
|
||||
@ -188,7 +180,6 @@ public class SQLiteDB extends SQLDB {
|
||||
private final NetworkContainer.Factory networkContainerFactory;
|
||||
private final RunnableFactory runnableFactory;
|
||||
private final PluginLogger logger;
|
||||
private final Timings timings;
|
||||
private final ErrorHandler errorHandler;
|
||||
private PlanFiles files;
|
||||
|
||||
@ -201,7 +192,6 @@ public class SQLiteDB extends SQLDB {
|
||||
NetworkContainer.Factory networkContainerFactory,
|
||||
RunnableFactory runnableFactory,
|
||||
PluginLogger logger,
|
||||
Timings timings,
|
||||
ErrorHandler errorHandler
|
||||
) {
|
||||
this.locale = locale;
|
||||
@ -211,7 +201,6 @@ public class SQLiteDB extends SQLDB {
|
||||
this.networkContainerFactory = networkContainerFactory;
|
||||
this.runnableFactory = runnableFactory;
|
||||
this.logger = logger;
|
||||
this.timings = timings;
|
||||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
@ -227,7 +216,7 @@ public class SQLiteDB extends SQLDB {
|
||||
return new SQLiteDB(databaseFile,
|
||||
locale, config, serverInfo,
|
||||
networkContainerFactory,
|
||||
runnableFactory, logger, timings, errorHandler
|
||||
runnableFactory, logger, errorHandler
|
||||
);
|
||||
}
|
||||
|
@ -14,21 +14,24 @@
|
||||
* 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.utilities.comparators;
|
||||
package com.djrapitops.plan.db.access;
|
||||
|
||||
import com.djrapitops.plan.data.container.UserInfo;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Comparator for UserInfo so that most recently seen is first.
|
||||
* SQL executing batch statement that closes appropriate elements.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class UserInfoLastPlayedComparator implements Comparator<UserInfo> {
|
||||
public abstract class ExecBatchStatement extends ExecStatement {
|
||||
|
||||
public ExecBatchStatement(String sql) {
|
||||
super(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(UserInfo u1, UserInfo u2) {
|
||||
return Long.compare(u2.getLastSeen(), u1.getLastSeen());
|
||||
protected boolean callExecute(PreparedStatement statement) throws SQLException {
|
||||
return statement.executeBatch().length > 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -14,8 +14,11 @@
|
||||
* 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.system.database.databases.sql.processing;
|
||||
package com.djrapitops.plan.db.access;
|
||||
|
||||
import com.djrapitops.plan.api.exceptions.database.DBOpException;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
@ -24,24 +27,35 @@ import java.sql.SQLException;
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public abstract class ExecStatement extends AbstractSQLStatement {
|
||||
public abstract class ExecStatement implements Executable {
|
||||
|
||||
private final String sql;
|
||||
|
||||
public ExecStatement(String sql) {
|
||||
super(sql);
|
||||
this.sql = sql;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(Connection connection) {
|
||||
try {
|
||||
try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
|
||||
return execute(preparedStatement);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw DBOpException.forCause(sql, e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean execute(PreparedStatement statement) throws SQLException {
|
||||
startBenchmark();
|
||||
try {
|
||||
prepare(statement);
|
||||
return callExecute(statement);
|
||||
} finally {
|
||||
statement.close();
|
||||
stopBenchmark();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean callExecute(PreparedStatement statement) throws SQLException {
|
||||
protected boolean callExecute(PreparedStatement statement) throws SQLException {
|
||||
if (sql.startsWith("UPDATE") || sql.startsWith("INSERT") || sql.startsWith("DELETE") || sql.startsWith("REPLACE")) {
|
||||
return statement.executeUpdate() > 0;
|
||||
} else {
|
||||
@ -50,17 +64,6 @@ public abstract class ExecStatement extends AbstractSQLStatement {
|
||||
}
|
||||
}
|
||||
|
||||
public void executeBatch(PreparedStatement statement) throws SQLException {
|
||||
startBatchBenchmark();
|
||||
try {
|
||||
prepare(statement);
|
||||
statement.executeBatch();
|
||||
} finally {
|
||||
statement.close();
|
||||
stopBatchBenchmark();
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void prepare(PreparedStatement statement) throws SQLException;
|
||||
|
||||
public String getSql() {
|
@ -14,15 +14,21 @@
|
||||
* 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.system.database.databases.operation;
|
||||
package com.djrapitops.plan.db.access;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.sql.Connection;
|
||||
|
||||
public interface RemoveOperations {
|
||||
/**
|
||||
* Interface for everything that updates rows in the database.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public interface Executable {
|
||||
|
||||
void player(UUID uuid);
|
||||
boolean execute(Connection connection);
|
||||
|
||||
void everything();
|
||||
static Executable empty() {
|
||||
return i -> true;
|
||||
}
|
||||
|
||||
void webUser(String name);
|
||||
}
|
@ -14,33 +14,31 @@
|
||||
* 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.system.processing.processors.player;
|
||||
package com.djrapitops.plan.db.access;
|
||||
|
||||
import com.djrapitops.plan.system.cache.SessionCache;
|
||||
import com.djrapitops.plan.system.processing.CriticalRunnable;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Ends a session and saves it to the database.
|
||||
* SQL query of a COUNT statement that closes proper elements.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class EndSessionProcessor implements CriticalRunnable {
|
||||
public abstract class HasMoreThanZeroQueryStatement extends QueryStatement<Boolean> {
|
||||
|
||||
private final UUID uuid;
|
||||
private final long time;
|
||||
private String countColumnName = "c";
|
||||
|
||||
private final SessionCache sessionCache;
|
||||
public HasMoreThanZeroQueryStatement(String sql) {
|
||||
super(sql);
|
||||
}
|
||||
|
||||
EndSessionProcessor(UUID uuid, long time, SessionCache sessionCache) {
|
||||
this.uuid = uuid;
|
||||
this.time = time;
|
||||
this.sessionCache = sessionCache;
|
||||
public HasMoreThanZeroQueryStatement(String sql, String countColumnName) {
|
||||
super(sql);
|
||||
this.countColumnName = countColumnName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
sessionCache.endSession(uuid, time);
|
||||
public Boolean processResults(ResultSet set) throws SQLException {
|
||||
return set.next() && set.getInt(countColumnName) > 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -14,19 +14,18 @@
|
||||
* 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.system.database.databases.sql.statements;
|
||||
package com.djrapitops.plan.db.access;
|
||||
|
||||
import com.djrapitops.plan.db.SQLDB;
|
||||
|
||||
/**
|
||||
* Interface for SQL column enum compatibility.
|
||||
* Interface for everything that returns results from the database.
|
||||
*
|
||||
* @param <T> Type of the result.
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public interface Column {
|
||||
public interface Query<T> {
|
||||
|
||||
default String get() {
|
||||
return toString();
|
||||
}
|
||||
|
||||
String toString();
|
||||
T executeQuery(SQLDB db);
|
||||
|
||||
}
|
@ -14,7 +14,7 @@
|
||||
* 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.system.database.databases.sql.processing;
|
||||
package com.djrapitops.plan.db.access;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
@ -14,8 +14,12 @@
|
||||
* 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.system.database.databases.sql.processing;
|
||||
package com.djrapitops.plan.db.access;
|
||||
|
||||
import com.djrapitops.plan.api.exceptions.database.DBOpException;
|
||||
import com.djrapitops.plan.db.SQLDB;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
@ -25,8 +29,9 @@ import java.sql.SQLException;
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public abstract class QueryStatement<T> extends AbstractSQLStatement {
|
||||
public abstract class QueryStatement<T> implements Query<T> {
|
||||
|
||||
private final String sql;
|
||||
private final int fetchSize;
|
||||
|
||||
public QueryStatement(String sql) {
|
||||
@ -34,12 +39,26 @@ public abstract class QueryStatement<T> extends AbstractSQLStatement {
|
||||
}
|
||||
|
||||
public QueryStatement(String sql, int fetchSize) {
|
||||
super(sql);
|
||||
this.sql = sql;
|
||||
this.fetchSize = fetchSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T executeQuery(SQLDB db) {
|
||||
Connection connection = null;
|
||||
try {
|
||||
connection = db.getConnection();
|
||||
try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
|
||||
return executeQuery(preparedStatement);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw DBOpException.forCause(sql, e);
|
||||
} finally {
|
||||
db.returnToPool(connection);
|
||||
}
|
||||
}
|
||||
|
||||
public T executeQuery(PreparedStatement statement) throws SQLException {
|
||||
startBenchmark();
|
||||
try {
|
||||
statement.setFetchSize(fetchSize);
|
||||
prepare(statement);
|
||||
@ -48,7 +67,6 @@ public abstract class QueryStatement<T> extends AbstractSQLStatement {
|
||||
}
|
||||
} finally {
|
||||
statement.close();
|
||||
stopBenchmark();
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,4 +77,9 @@ public abstract class QueryStatement<T> extends AbstractSQLStatement {
|
||||
public String getSql() {
|
||||
return sql;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Query (" + sql + ')';
|
||||
}
|
||||
}
|
@ -0,0 +1,331 @@
|
||||
/*
|
||||
* 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.db.access.queries;
|
||||
|
||||
import com.djrapitops.plan.data.container.GeoInfo;
|
||||
import com.djrapitops.plan.data.container.Ping;
|
||||
import com.djrapitops.plan.data.container.Session;
|
||||
import com.djrapitops.plan.data.container.TPS;
|
||||
import com.djrapitops.plan.data.store.keys.SessionKeys;
|
||||
import com.djrapitops.plan.data.store.objects.Nickname;
|
||||
import com.djrapitops.plan.data.time.GMTimes;
|
||||
import com.djrapitops.plan.db.access.ExecBatchStatement;
|
||||
import com.djrapitops.plan.db.access.ExecStatement;
|
||||
import com.djrapitops.plan.db.access.Executable;
|
||||
import com.djrapitops.plan.db.sql.tables.*;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Static method class for single item store queries.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class DataStoreQueries {
|
||||
|
||||
private DataStoreQueries() {
|
||||
/* static method class */
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the used command in the database.
|
||||
*
|
||||
* @param serverUUID UUID of the Plan server.
|
||||
* @param commandName Name of the command that was used.
|
||||
* @return Executable, use inside a {@link com.djrapitops.plan.db.access.transactions.Transaction}
|
||||
*/
|
||||
public static Executable storeUsedCommandInformation(UUID serverUUID, String commandName) {
|
||||
return connection -> {
|
||||
if (!updateCommandUsage(serverUUID, commandName).execute(connection)) {
|
||||
insertNewCommandUsage(serverUUID, commandName).execute(connection);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
private static Executable updateCommandUsage(UUID serverUUID, String commandName) {
|
||||
return new ExecStatement(CommandUseTable.UPDATE_STATEMENT) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, serverUUID.toString());
|
||||
statement.setString(2, commandName);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static Executable insertNewCommandUsage(UUID serverUUID, String commandName) {
|
||||
return new ExecStatement(CommandUseTable.INSERT_STATEMENT) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, commandName);
|
||||
statement.setInt(2, 1);
|
||||
statement.setString(3, serverUUID.toString());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a finished session in the database.
|
||||
*
|
||||
* @param session Session, of which {@link Session#endSession(long)} has been called.
|
||||
* @return Executable, use inside a {@link com.djrapitops.plan.db.access.transactions.Transaction}
|
||||
* @throws IllegalArgumentException If {@link Session#endSession(long)} has not yet been called.
|
||||
*/
|
||||
public static Executable storeSession(Session session) {
|
||||
session.getValue(SessionKeys.END).orElseThrow(() -> new IllegalArgumentException("Attempted to save a session that has not ended."));
|
||||
return connection -> {
|
||||
storeSessionInformation(session).execute(connection);
|
||||
storeSessionKills(session).execute(connection);
|
||||
return storeSessionWorldTimes(session).execute(connection);
|
||||
};
|
||||
}
|
||||
|
||||
private static Executable storeSessionInformation(Session session) {
|
||||
return new ExecStatement(SessionsTable.INSERT_STATEMENT) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, session.getUnsafe(SessionKeys.UUID).toString());
|
||||
statement.setLong(2, session.getUnsafe(SessionKeys.START));
|
||||
statement.setLong(3, session.getUnsafe(SessionKeys.END));
|
||||
statement.setInt(4, session.getUnsafe(SessionKeys.DEATH_COUNT));
|
||||
statement.setInt(5, session.getUnsafe(SessionKeys.MOB_KILL_COUNT));
|
||||
statement.setLong(6, session.getUnsafe(SessionKeys.AFK_TIME));
|
||||
statement.setString(7, session.getUnsafe(SessionKeys.SERVER_UUID).toString());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static Executable storeSessionKills(Session session) {
|
||||
return new ExecBatchStatement(KillsTable.INSERT_STATEMENT) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
KillsTable.addSessionKillsToBatch(statement, session);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Executable insertWorldName(UUID serverUUID, String worldName) {
|
||||
return new ExecStatement(WorldTable.INSERT_STATEMENT) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, worldName);
|
||||
statement.setString(2, serverUUID.toString());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static Executable storeSessionWorldTimes(Session session) {
|
||||
if (session.getValue(SessionKeys.WORLD_TIMES).map(times -> times.getWorldTimes().isEmpty()).orElse(true)) {
|
||||
return Executable.empty();
|
||||
}
|
||||
return new ExecBatchStatement(WorldTimesTable.INSERT_STATEMENT) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
WorldTimesTable.addSessionWorldTimesToBatch(statement, session, GMTimes.getGMKeyArray());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Store player's Geo Information in the database.
|
||||
*
|
||||
* @param playerUUID UUID of the player.
|
||||
* @param geoInfo GeoInfo of the player.
|
||||
* @return Executable, use inside a {@link com.djrapitops.plan.db.access.transactions.Transaction}
|
||||
*/
|
||||
public static Executable storeGeoInfo(UUID playerUUID, GeoInfo geoInfo) {
|
||||
return connection -> {
|
||||
if (!updateGeoInfo(playerUUID, geoInfo).execute(connection)) {
|
||||
return insertGeoInfo(playerUUID, geoInfo).execute(connection);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
private static Executable updateGeoInfo(UUID playerUUID, GeoInfo geoInfo) {
|
||||
return new ExecStatement(GeoInfoTable.UPDATE_STATEMENT) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setLong(1, geoInfo.getDate());
|
||||
statement.setString(2, playerUUID.toString());
|
||||
statement.setString(3, geoInfo.getIpHash());
|
||||
statement.setString(4, geoInfo.getGeolocation());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static Executable insertGeoInfo(UUID playerUUID, GeoInfo geoInfo) {
|
||||
return new ExecStatement(GeoInfoTable.INSERT_STATEMENT) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, playerUUID.toString());
|
||||
statement.setString(2, geoInfo.getIp());
|
||||
statement.setString(3, geoInfo.getIpHash());
|
||||
statement.setString(4, geoInfo.getGeolocation());
|
||||
statement.setLong(5, geoInfo.getDate());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a BaseUser for the player in the database.
|
||||
*
|
||||
* @param playerUUID UUID of the player.
|
||||
* @param registered Time the player registered on the server for the first time.
|
||||
* @param playerName Name of the player.
|
||||
* @return Executable, use inside a {@link com.djrapitops.plan.db.access.transactions.Transaction}
|
||||
*/
|
||||
public static Executable registerBaseUser(UUID playerUUID, long registered, String playerName) {
|
||||
return new ExecStatement(UsersTable.INSERT_STATEMENT) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, playerUUID.toString());
|
||||
statement.setString(2, playerName);
|
||||
statement.setLong(3, registered);
|
||||
statement.setInt(4, 0); // times kicked
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Update player's name in the database in case they have changed it.
|
||||
*
|
||||
* @param playerUUID UUID of the player.
|
||||
* @param playerName Name of the player.
|
||||
* @return Executable, use inside a {@link com.djrapitops.plan.db.access.transactions.Transaction}
|
||||
*/
|
||||
public static Executable updatePlayerName(UUID playerUUID, String playerName) {
|
||||
String sql = "UPDATE " + UsersTable.TABLE_NAME + " SET " + UsersTable.USER_NAME + "=?" +
|
||||
" WHERE " + UsersTable.USER_UUID + "=?";
|
||||
return new ExecStatement(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, playerName);
|
||||
statement.setString(2, playerUUID.toString());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Store UserInfo about a player on a server in the database.
|
||||
*
|
||||
* @param playerUUID UUID of the player.
|
||||
* @param registered Time the player registered on the server.
|
||||
* @param serverUUID UUID of the Plan server.
|
||||
* @return Executable, use inside a {@link com.djrapitops.plan.db.access.transactions.Transaction}
|
||||
*/
|
||||
public static Executable registerUserInfo(UUID playerUUID, long registered, UUID serverUUID) {
|
||||
return new ExecStatement(UserInfoTable.INSERT_STATEMENT) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, playerUUID.toString());
|
||||
statement.setLong(2, registered);
|
||||
statement.setString(3, serverUUID.toString());
|
||||
statement.setBoolean(4, false); // Banned
|
||||
statement.setBoolean(5, false); // Operator
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Store Ping data of a player on a server.
|
||||
*
|
||||
* @param playerUUID UUID of the player.
|
||||
* @param serverUUID UUID of the Plan server.
|
||||
* @param ping Ping data entry
|
||||
* @return Executable, use inside a {@link com.djrapitops.plan.db.access.transactions.Transaction}
|
||||
*/
|
||||
public static Executable storePing(UUID playerUUID, UUID serverUUID, Ping ping) {
|
||||
return new ExecStatement(PingTable.INSERT_STATEMENT) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, playerUUID.toString());
|
||||
statement.setString(2, serverUUID.toString());
|
||||
statement.setLong(3, ping.getDate());
|
||||
statement.setInt(4, ping.getMin());
|
||||
statement.setInt(5, ping.getMax());
|
||||
statement.setDouble(6, ping.getAverage());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Store TPS data of a server.
|
||||
*
|
||||
* @param serverUUID UUID of the Plan server.
|
||||
* @param tps TPS data entry
|
||||
* @return Executable, use inside a {@link com.djrapitops.plan.db.access.transactions.Transaction}
|
||||
*/
|
||||
public static Executable storeTPS(UUID serverUUID, TPS tps) {
|
||||
return new ExecStatement(TPSTable.INSERT_STATEMENT) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, serverUUID.toString());
|
||||
statement.setLong(2, tps.getDate());
|
||||
statement.setDouble(3, tps.getTicksPerSecond());
|
||||
statement.setInt(4, tps.getPlayers());
|
||||
statement.setDouble(5, tps.getCPUUsage());
|
||||
statement.setLong(6, tps.getUsedMemory());
|
||||
statement.setDouble(7, tps.getEntityCount());
|
||||
statement.setDouble(8, tps.getChunksLoaded());
|
||||
statement.setLong(9, tps.getFreeDiskSpace());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Store nickname information of a player on a server.
|
||||
*
|
||||
* @param playerUUID UUID of the player.
|
||||
* @param nickname Nickname information.
|
||||
* @return Executable, use inside a {@link com.djrapitops.plan.db.access.transactions.Transaction}
|
||||
*/
|
||||
public static Executable storePlayerNickname(UUID playerUUID, Nickname nickname) {
|
||||
return connection -> {
|
||||
if (!updatePlayerNickname(playerUUID, nickname).execute(connection)) {
|
||||
insertPlayerNickname(playerUUID, nickname).execute(connection);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
private static Executable updatePlayerNickname(UUID playerUUID, Nickname nickname) {
|
||||
return new ExecStatement(NicknamesTable.UPDATE_STATEMENT) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setLong(1, nickname.getDate());
|
||||
statement.setString(2, nickname.getName());
|
||||
statement.setString(3, playerUUID.toString());
|
||||
statement.setString(4, nickname.getServerUUID().toString());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static Executable insertPlayerNickname(UUID playerUUID, Nickname nickname) {
|
||||
return new ExecStatement(NicknamesTable.INSERT_STATEMENT) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, playerUUID.toString());
|
||||
statement.setString(2, nickname.getServerUUID().toString());
|
||||
statement.setString(3, nickname.getName());
|
||||
statement.setLong(4, nickname.getDate());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* 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.db.access.queries;
|
||||
|
||||
import com.djrapitops.plan.data.container.TPS;
|
||||
import com.djrapitops.plan.data.container.builders.TPSBuilder;
|
||||
import com.djrapitops.plan.db.access.Query;
|
||||
import com.djrapitops.plan.db.access.QueryAllStatement;
|
||||
import com.djrapitops.plan.db.sql.tables.CommandUseTable;
|
||||
import com.djrapitops.plan.db.sql.tables.ServerTable;
|
||||
import com.djrapitops.plan.db.sql.tables.TPSTable;
|
||||
import com.djrapitops.plan.db.sql.tables.WorldTable;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Static method class for queries that use large amount of memory.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class LargeFetchQueries {
|
||||
|
||||
private LargeFetchQueries() {
|
||||
/* Static method class */
|
||||
}
|
||||
|
||||
/**
|
||||
* Query database for all command usage data.
|
||||
*
|
||||
* @return Multi map: Server UUID - (Command name - Usage count)
|
||||
*/
|
||||
public static Query<Map<UUID, Map<String, Integer>>> fetchAllCommandUsageData() {
|
||||
String serverIDColumn = ServerTable.TABLE_NAME + "." + ServerTable.SERVER_ID;
|
||||
String serverUUIDColumn = ServerTable.TABLE_NAME + "." + ServerTable.SERVER_UUID + " as s_uuid";
|
||||
String sql = "SELECT " +
|
||||
CommandUseTable.COMMAND + ", " +
|
||||
CommandUseTable.TIMES_USED + ", " +
|
||||
serverUUIDColumn +
|
||||
" FROM " + CommandUseTable.TABLE_NAME +
|
||||
" INNER JOIN " + ServerTable.TABLE_NAME + " on " + serverIDColumn + "=" + CommandUseTable.SERVER_ID;
|
||||
|
||||
return new QueryAllStatement<Map<UUID, Map<String, Integer>>>(sql, 10000) {
|
||||
@Override
|
||||
public Map<UUID, Map<String, Integer>> processResults(ResultSet set) throws SQLException {
|
||||
Map<UUID, Map<String, Integer>> map = new HashMap<>();
|
||||
while (set.next()) {
|
||||
UUID serverUUID = UUID.fromString(set.getString("s_uuid"));
|
||||
|
||||
Map<String, Integer> serverMap = map.getOrDefault(serverUUID, new HashMap<>());
|
||||
|
||||
String command = set.getString(CommandUseTable.COMMAND);
|
||||
int timesUsed = set.getInt(CommandUseTable.TIMES_USED);
|
||||
|
||||
serverMap.put(command, timesUsed);
|
||||
map.put(serverUUID, serverMap);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Query database for TPS data.
|
||||
*
|
||||
* @return Map: Server UUID - List of TPS data
|
||||
*/
|
||||
public static Query<Map<UUID, List<TPS>>> fetchAllTPSData() {
|
||||
String serverIDColumn = ServerTable.TABLE_NAME + "." + ServerTable.SERVER_ID;
|
||||
String serverUUIDColumn = ServerTable.TABLE_NAME + "." + ServerTable.SERVER_UUID + " as s_uuid";
|
||||
String sql = "SELECT " +
|
||||
TPSTable.DATE + ", " +
|
||||
TPSTable.TPS + ", " +
|
||||
TPSTable.PLAYERS_ONLINE + ", " +
|
||||
TPSTable.CPU_USAGE + ", " +
|
||||
TPSTable.RAM_USAGE + ", " +
|
||||
TPSTable.ENTITIES + ", " +
|
||||
TPSTable.CHUNKS + ", " +
|
||||
TPSTable.FREE_DISK + ", " +
|
||||
serverUUIDColumn +
|
||||
" FROM " + TPSTable.TABLE_NAME +
|
||||
" INNER JOIN " + ServerTable.TABLE_NAME + " on " + serverIDColumn + "=" + TPSTable.SERVER_ID;
|
||||
|
||||
return new QueryAllStatement<Map<UUID, List<TPS>>>(sql, 50000) {
|
||||
@Override
|
||||
public Map<UUID, List<TPS>> processResults(ResultSet set) throws SQLException {
|
||||
Map<UUID, List<TPS>> serverMap = new HashMap<>();
|
||||
while (set.next()) {
|
||||
UUID serverUUID = UUID.fromString(set.getString("s_uuid"));
|
||||
|
||||
List<TPS> tpsList = serverMap.getOrDefault(serverUUID, new ArrayList<>());
|
||||
|
||||
TPS tps = TPSBuilder.get()
|
||||
.date(set.getLong(TPSTable.DATE))
|
||||
.tps(set.getDouble(TPSTable.TPS))
|
||||
.playersOnline(set.getInt(TPSTable.PLAYERS_ONLINE))
|
||||
.usedCPU(set.getDouble(TPSTable.CPU_USAGE))
|
||||
.usedMemory(set.getLong(TPSTable.RAM_USAGE))
|
||||
.entities(set.getInt(TPSTable.ENTITIES))
|
||||
.chunksLoaded(set.getInt(TPSTable.CHUNKS))
|
||||
.freeDiskSpace(set.getLong(TPSTable.FREE_DISK))
|
||||
.toTPS();
|
||||
|
||||
tpsList.add(tps);
|
||||
serverMap.put(serverUUID, tpsList);
|
||||
}
|
||||
return serverMap;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Query database for world names.
|
||||
*
|
||||
* @return Map: Server UUID - List of world names
|
||||
*/
|
||||
public static Query<Map<UUID, Collection<String>>> fetchAllWorldNames() {
|
||||
String sql = "SELECT * FROM " + WorldTable.TABLE_NAME;
|
||||
|
||||
return new QueryAllStatement<Map<UUID, Collection<String>>>(sql, 1000) {
|
||||
@Override
|
||||
public Map<UUID, Collection<String>> processResults(ResultSet set) throws SQLException {
|
||||
Map<UUID, Collection<String>> worldMap = new HashMap<>();
|
||||
while (set.next()) {
|
||||
UUID serverUUID = UUID.fromString(set.getString(WorldTable.SERVER_UUID));
|
||||
Collection<String> worlds = worldMap.getOrDefault(serverUUID, new HashSet<>());
|
||||
worlds.add(set.getString(WorldTable.NAME));
|
||||
worldMap.put(serverUUID, worlds);
|
||||
}
|
||||
return worldMap;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,424 @@
|
||||
/*
|
||||
* 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.db.access.queries;
|
||||
|
||||
import com.djrapitops.plan.data.WebUser;
|
||||
import com.djrapitops.plan.data.container.*;
|
||||
import com.djrapitops.plan.data.store.keys.SessionKeys;
|
||||
import com.djrapitops.plan.data.store.objects.Nickname;
|
||||
import com.djrapitops.plan.data.time.GMTimes;
|
||||
import com.djrapitops.plan.db.access.ExecBatchStatement;
|
||||
import com.djrapitops.plan.db.access.Executable;
|
||||
import com.djrapitops.plan.db.sql.tables.*;
|
||||
import com.djrapitops.plan.system.info.server.Server;
|
||||
import com.djrapitops.plugin.utilities.Verify;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Static method class for large storage queries.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class LargeStoreQueries {
|
||||
|
||||
private LargeStoreQueries() {
|
||||
/* Static method class */
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a big batch of command use insert statements.
|
||||
*
|
||||
* @param ofServers Multi map: Server UUID - (Command name - Usage count)
|
||||
* @return Executable, use inside a {@link com.djrapitops.plan.db.access.transactions.Transaction}
|
||||
*/
|
||||
public static Executable storeAllCommandUsageData(Map<UUID, Map<String, Integer>> ofServers) {
|
||||
if (ofServers.isEmpty()) {
|
||||
return Executable.empty();
|
||||
}
|
||||
|
||||
return new ExecBatchStatement(CommandUseTable.INSERT_STATEMENT) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
// Every Server
|
||||
for (Map.Entry<UUID, Map<String, Integer>> serverEntry : ofServers.entrySet()) {
|
||||
UUID serverUUID = serverEntry.getKey();
|
||||
// Every Command
|
||||
for (Map.Entry<String, Integer> entry : serverEntry.getValue().entrySet()) {
|
||||
String command = entry.getKey();
|
||||
int timesUsed = entry.getValue();
|
||||
|
||||
statement.setString(1, command);
|
||||
statement.setInt(2, timesUsed);
|
||||
statement.setString(3, serverUUID.toString());
|
||||
statement.addBatch();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a big batch of GeoInfo insert statements.
|
||||
*
|
||||
* @param ofUsers Map: Player UUID - List of GeoInfo
|
||||
* @return Executable, use inside a {@link com.djrapitops.plan.db.access.transactions.Transaction}
|
||||
*/
|
||||
public static Executable storeAllGeoInformation(Map<UUID, List<GeoInfo>> ofUsers) {
|
||||
if (Verify.isEmpty(ofUsers)) {
|
||||
return Executable.empty();
|
||||
}
|
||||
|
||||
return new ExecBatchStatement(GeoInfoTable.INSERT_STATEMENT) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
// Every User
|
||||
for (Map.Entry<UUID, List<GeoInfo>> playerEntry : ofUsers.entrySet()) {
|
||||
UUID playerUUID = playerEntry.getKey();
|
||||
// Every GeoInfo
|
||||
for (GeoInfo info : playerEntry.getValue()) {
|
||||
String ip = info.getIp();
|
||||
String ipHash = info.getIpHash();
|
||||
String geoLocation = info.getGeolocation();
|
||||
long lastUsed = info.getDate();
|
||||
|
||||
statement.setString(1, playerUUID.toString());
|
||||
statement.setString(2, ip);
|
||||
statement.setString(3, ipHash);
|
||||
statement.setString(4, geoLocation);
|
||||
statement.setLong(5, lastUsed);
|
||||
|
||||
statement.addBatch();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a big batch of nickname insert statements.
|
||||
*
|
||||
* @param ofServersAndUsers Multimap: Server UUID - (Player UUID - List of nicknames)
|
||||
* @return Executable, use inside a {@link com.djrapitops.plan.db.access.transactions.Transaction}
|
||||
*/
|
||||
public static Executable storeAllNicknameData(Map<UUID, Map<UUID, List<Nickname>>> ofServersAndUsers) {
|
||||
if (Verify.isEmpty(ofServersAndUsers)) {
|
||||
return Executable.empty();
|
||||
}
|
||||
|
||||
return new ExecBatchStatement(NicknamesTable.INSERT_STATEMENT) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
// Every Server
|
||||
for (Map.Entry<UUID, Map<UUID, List<Nickname>>> serverEntry : ofServersAndUsers.entrySet()) {
|
||||
UUID serverUUID = serverEntry.getKey();
|
||||
// Every User
|
||||
for (Map.Entry<UUID, List<Nickname>> entry : serverEntry.getValue().entrySet()) {
|
||||
UUID uuid = entry.getKey();
|
||||
// Every Nickname
|
||||
List<Nickname> nicknames = entry.getValue();
|
||||
for (Nickname nickname : nicknames) {
|
||||
statement.setString(1, uuid.toString());
|
||||
statement.setString(2, serverUUID.toString());
|
||||
statement.setString(3, nickname.getName());
|
||||
statement.setLong(4, nickname.getDate());
|
||||
statement.addBatch();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a big batch of web user insert statements.
|
||||
*
|
||||
* @param users Collection of Plan WebUsers.
|
||||
* @return Executable, use inside a {@link com.djrapitops.plan.db.access.transactions.Transaction}
|
||||
*/
|
||||
public static Executable storeAllPlanWebUsers(Collection<WebUser> users) {
|
||||
if (Verify.isEmpty(users)) {
|
||||
return Executable.empty();
|
||||
}
|
||||
|
||||
return new ExecBatchStatement(SecurityTable.INSERT_STATEMENT) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
for (WebUser user : users) {
|
||||
String userName = user.getName();
|
||||
String pass = user.getSaltedPassHash();
|
||||
int permLvl = user.getPermLevel();
|
||||
|
||||
statement.setString(1, userName);
|
||||
statement.setString(2, pass);
|
||||
statement.setInt(3, permLvl);
|
||||
statement.addBatch();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a big batch of server infromation insert statements.
|
||||
*
|
||||
* @param servers Collection of Plan Servers.
|
||||
* @return Executable, use inside a {@link com.djrapitops.plan.db.access.transactions.Transaction}
|
||||
*/
|
||||
public static Executable storeAllPlanServerInformation(Collection<Server> servers) {
|
||||
if (Verify.isEmpty(servers)) {
|
||||
return Executable.empty();
|
||||
}
|
||||
|
||||
return new ExecBatchStatement(ServerTable.INSERT_STATEMENT) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
for (Server info : servers) {
|
||||
UUID uuid = info.getUuid();
|
||||
String name = info.getName();
|
||||
String webAddress = info.getWebAddress();
|
||||
|
||||
if (uuid == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
statement.setString(1, uuid.toString());
|
||||
statement.setString(2, name);
|
||||
statement.setString(3, webAddress);
|
||||
statement.setBoolean(4, true);
|
||||
statement.setInt(5, info.getMaxPlayers());
|
||||
statement.addBatch();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a big batch of TPS insert statements.
|
||||
*
|
||||
* @param ofServers Map: Server UUID - List of TPS data
|
||||
* @return Executable, use inside a {@link com.djrapitops.plan.db.access.transactions.Transaction}
|
||||
*/
|
||||
public static Executable storeAllTPSData(Map<UUID, List<TPS>> ofServers) {
|
||||
if (Verify.isEmpty(ofServers)) {
|
||||
return Executable.empty();
|
||||
}
|
||||
|
||||
return new ExecBatchStatement(TPSTable.INSERT_STATEMENT) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
// Every Server
|
||||
for (Map.Entry<UUID, List<TPS>> entry : ofServers.entrySet()) {
|
||||
UUID serverUUID = entry.getKey();
|
||||
// Every TPS Data point
|
||||
List<TPS> tpsList = entry.getValue();
|
||||
for (TPS tps : tpsList) {
|
||||
statement.setString(1, serverUUID.toString());
|
||||
statement.setLong(2, tps.getDate());
|
||||
statement.setDouble(3, tps.getTicksPerSecond());
|
||||
statement.setInt(4, tps.getPlayers());
|
||||
statement.setDouble(5, tps.getCPUUsage());
|
||||
statement.setLong(6, tps.getUsedMemory());
|
||||
statement.setDouble(7, tps.getEntityCount());
|
||||
statement.setDouble(8, tps.getChunksLoaded());
|
||||
statement.setLong(9, tps.getFreeDiskSpace());
|
||||
statement.addBatch();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a big batch of Per server UserInfo insert statements.
|
||||
*
|
||||
* @param ofServers Map: Server UUID - List of user information
|
||||
* @return Executable, use inside a {@link com.djrapitops.plan.db.access.transactions.Transaction}
|
||||
*/
|
||||
public static Executable storePerServerUserInformation(Map<UUID, List<UserInfo>> ofServers) {
|
||||
if (Verify.isEmpty(ofServers)) {
|
||||
return Executable.empty();
|
||||
}
|
||||
|
||||
return new ExecBatchStatement(UserInfoTable.INSERT_STATEMENT) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
// Every Server
|
||||
for (Map.Entry<UUID, List<UserInfo>> entry : ofServers.entrySet()) {
|
||||
UUID serverUUID = entry.getKey();
|
||||
// Every User
|
||||
for (UserInfo user : entry.getValue()) {
|
||||
statement.setString(1, user.getPlayerUuid().toString());
|
||||
statement.setLong(2, user.getRegistered());
|
||||
statement.setString(3, serverUUID.toString());
|
||||
statement.setBoolean(4, user.isBanned());
|
||||
statement.setBoolean(5, user.isOperator());
|
||||
statement.addBatch();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a big batch of world name insert statements.
|
||||
*
|
||||
* @param ofServers Map: Server UUID - Collection of world names
|
||||
* @return Executable, use inside a {@link com.djrapitops.plan.db.access.transactions.Transaction}
|
||||
*/
|
||||
public static Executable storeAllWorldNames(Map<UUID, Collection<String>> ofServers) {
|
||||
if (Verify.isEmpty(ofServers)) {
|
||||
return Executable.empty();
|
||||
}
|
||||
|
||||
return new ExecBatchStatement(WorldTable.INSERT_STATEMENT) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
for (Map.Entry<UUID, Collection<String>> entry : ofServers.entrySet()) {
|
||||
UUID serverUUID = entry.getKey();
|
||||
for (String world : entry.getValue()) {
|
||||
statement.setString(1, world);
|
||||
statement.setString(2, serverUUID.toString());
|
||||
statement.addBatch();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a big batch of user information insert statements.
|
||||
*
|
||||
* @param ofUsers Collection of BaseUsers
|
||||
* @return Executable, use inside a {@link com.djrapitops.plan.db.access.transactions.Transaction}
|
||||
*/
|
||||
public static Executable storeAllCommonUserInformation(Collection<BaseUser> ofUsers) {
|
||||
if (Verify.isEmpty(ofUsers)) {
|
||||
return Executable.empty();
|
||||
}
|
||||
|
||||
return new ExecBatchStatement(UsersTable.INSERT_STATEMENT) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
for (BaseUser user : ofUsers) {
|
||||
statement.setString(1, user.getUuid().toString());
|
||||
statement.setString(2, user.getName());
|
||||
statement.setLong(3, user.getRegistered());
|
||||
statement.setInt(4, user.getTimesKicked());
|
||||
statement.addBatch();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Executable storeAllSessionsWithoutKillOrWorldData(Collection<Session> sessions) {
|
||||
if (Verify.isEmpty(sessions)) {
|
||||
return Executable.empty();
|
||||
}
|
||||
|
||||
return new ExecBatchStatement(SessionsTable.INSERT_STATEMENT) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
for (Session session : sessions) {
|
||||
statement.setString(1, session.getUnsafe(SessionKeys.UUID).toString());
|
||||
statement.setLong(2, session.getUnsafe(SessionKeys.START));
|
||||
statement.setLong(3, session.getUnsafe(SessionKeys.END));
|
||||
statement.setInt(4, session.getUnsafe(SessionKeys.DEATH_COUNT));
|
||||
statement.setInt(5, session.getUnsafe(SessionKeys.MOB_KILL_COUNT));
|
||||
statement.setLong(6, session.getUnsafe(SessionKeys.AFK_TIME));
|
||||
statement.setString(7, session.getUnsafe(SessionKeys.SERVER_UUID).toString());
|
||||
statement.addBatch();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Executable storeAllSessionsWithKillAndWorldData(Collection<Session> sessions) {
|
||||
return connection -> {
|
||||
storeAllSessionsWithoutKillOrWorldData(sessions).execute(connection);
|
||||
storeSessionKillData(sessions).execute(connection);
|
||||
return storeSessionWorldTimeData(sessions).execute(connection);
|
||||
};
|
||||
}
|
||||
|
||||
private static Executable storeSessionKillData(Collection<Session> sessions) {
|
||||
if (Verify.isEmpty(sessions)) {
|
||||
return Executable.empty();
|
||||
}
|
||||
|
||||
return new ExecBatchStatement(KillsTable.INSERT_STATEMENT) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
for (Session session : sessions) {
|
||||
KillsTable.addSessionKillsToBatch(statement, session);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static Executable storeSessionWorldTimeData(Collection<Session> sessions) {
|
||||
if (Verify.isEmpty(sessions)) {
|
||||
return Executable.empty();
|
||||
}
|
||||
|
||||
return new ExecBatchStatement(WorldTimesTable.INSERT_STATEMENT) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
String[] gms = GMTimes.getGMKeyArray();
|
||||
|
||||
for (Session session : sessions) {
|
||||
WorldTimesTable.addSessionWorldTimesToBatch(statement, session, gms);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Executable storeAllPingData(Map<UUID, List<Ping>> ofUsers) {
|
||||
if (Verify.isEmpty(ofUsers)) {
|
||||
return Executable.empty();
|
||||
}
|
||||
|
||||
return new ExecBatchStatement(PingTable.INSERT_STATEMENT) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
for (Map.Entry<UUID, List<Ping>> entry : ofUsers.entrySet()) {
|
||||
UUID uuid = entry.getKey();
|
||||
List<Ping> pings = entry.getValue();
|
||||
for (Ping ping : pings) {
|
||||
UUID serverUUID = ping.getServerUUID();
|
||||
long date = ping.getDate();
|
||||
int minPing = ping.getMin();
|
||||
int maxPing = ping.getMax();
|
||||
double avgPing = ping.getAverage();
|
||||
|
||||
statement.setString(1, uuid.toString());
|
||||
statement.setString(2, serverUUID.toString());
|
||||
statement.setLong(3, date);
|
||||
statement.setInt(4, minPing);
|
||||
statement.setInt(5, maxPing);
|
||||
statement.setDouble(6, avgPing);
|
||||
statement.addBatch();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,190 @@
|
||||
/*
|
||||
* 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.db.access.queries;
|
||||
|
||||
import com.djrapitops.plan.db.access.Query;
|
||||
import com.djrapitops.plan.db.access.QueryStatement;
|
||||
import com.djrapitops.plan.db.sql.tables.KillsTable;
|
||||
import com.djrapitops.plan.db.sql.tables.SessionsTable;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.djrapitops.plan.db.sql.parsing.Sql.*;
|
||||
|
||||
/**
|
||||
* Static method class for queries that count together counts for a player on a per server basis.
|
||||
* <p>
|
||||
* Example:
|
||||
* Fetch how much a player has played on servers
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class PerServerAggregateQueries {
|
||||
|
||||
private PerServerAggregateQueries() {
|
||||
/* Static method class */
|
||||
}
|
||||
|
||||
/**
|
||||
* Find last seen date on servers.
|
||||
*
|
||||
* @param playerUUID UUID of the player.
|
||||
* @return Map: Server UUID - Last seen epoch ms.
|
||||
*/
|
||||
public static Query<Map<UUID, Long>> lastSeenOnServers(UUID playerUUID) {
|
||||
String sql = "SELECT MAX(" + SessionsTable.SESSION_END + ") as last_seen, " +
|
||||
SessionsTable.SERVER_UUID +
|
||||
FROM + SessionsTable.TABLE_NAME +
|
||||
WHERE + SessionsTable.USER_UUID + "=?" +
|
||||
GROUP_BY + SessionsTable.SERVER_UUID;
|
||||
return new QueryStatement<Map<UUID, Long>>(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, playerUUID.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<UUID, Long> processResults(ResultSet set) throws SQLException {
|
||||
Map<UUID, Long> lastSeenMap = new HashMap<>();
|
||||
while (set.next()) {
|
||||
UUID serverUUID = UUID.fromString(set.getString(SessionsTable.SERVER_UUID));
|
||||
long lastSeen = set.getLong("last_seen");
|
||||
lastSeenMap.put(serverUUID, lastSeen);
|
||||
}
|
||||
return lastSeenMap;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Find player kill count on servers.
|
||||
*
|
||||
* @param playerUUID UUID of the player.
|
||||
* @return Map: Server UUID - Player kill count
|
||||
*/
|
||||
public static Query<Map<UUID, Integer>> playerKillCountOnServers(UUID playerUUID) {
|
||||
String sql = "SELECT COUNT(1) as kill_count, " + KillsTable.SERVER_UUID + FROM + KillsTable.TABLE_NAME +
|
||||
WHERE + KillsTable.KILLER_UUID + "=?" +
|
||||
GROUP_BY + KillsTable.SERVER_UUID;
|
||||
return new QueryStatement<Map<UUID, Integer>>(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, playerUUID.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<UUID, Integer> processResults(ResultSet set) throws SQLException {
|
||||
Map<UUID, Integer> killCountMap = new HashMap<>();
|
||||
while (set.next()) {
|
||||
UUID serverUUID = UUID.fromString(set.getString(SessionsTable.SERVER_UUID));
|
||||
int lastSeen = set.getInt("kill_count");
|
||||
killCountMap.put(serverUUID, lastSeen);
|
||||
}
|
||||
return killCountMap;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Find mob kill count on servers.
|
||||
*
|
||||
* @param playerUUID UUID of the player.
|
||||
* @return Map: Server UUID - Mob kill count
|
||||
*/
|
||||
public static Query<Map<UUID, Integer>> mobKillCountOnServers(UUID playerUUID) {
|
||||
String sql = "SELECT SUM(" + SessionsTable.MOB_KILLS + ") as kill_count, " +
|
||||
SessionsTable.SERVER_UUID + FROM + SessionsTable.TABLE_NAME +
|
||||
WHERE + SessionsTable.USER_UUID + "=?" +
|
||||
GROUP_BY + SessionsTable.SERVER_UUID;
|
||||
return new QueryStatement<Map<UUID, Integer>>(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, playerUUID.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<UUID, Integer> processResults(ResultSet set) throws SQLException {
|
||||
Map<UUID, Integer> killCountMap = new HashMap<>();
|
||||
while (set.next()) {
|
||||
UUID serverUUID = UUID.fromString(set.getString(SessionsTable.SERVER_UUID));
|
||||
int lastSeen = set.getInt("kill_count");
|
||||
killCountMap.put(serverUUID, lastSeen);
|
||||
}
|
||||
return killCountMap;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Find how many times a player killed the player on servers.
|
||||
*
|
||||
* @param playerUUID UUID of the player.
|
||||
* @return Map: Server UUID - Mob kill count
|
||||
*/
|
||||
public static Query<Map<UUID, Integer>> playerDeathCountOnServers(UUID playerUUID) {
|
||||
String sql = "SELECT COUNT(1) as death_count, " + KillsTable.SERVER_UUID + FROM + KillsTable.TABLE_NAME +
|
||||
WHERE + KillsTable.VICTIM_UUID + "=?" +
|
||||
GROUP_BY + KillsTable.SERVER_UUID;
|
||||
return new QueryStatement<Map<UUID, Integer>>(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, playerUUID.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<UUID, Integer> processResults(ResultSet set) throws SQLException {
|
||||
Map<UUID, Integer> killCountMap = new HashMap<>();
|
||||
while (set.next()) {
|
||||
UUID serverUUID = UUID.fromString(set.getString(SessionsTable.SERVER_UUID));
|
||||
int lastSeen = set.getInt("death_count");
|
||||
killCountMap.put(serverUUID, lastSeen);
|
||||
}
|
||||
return killCountMap;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Query<Map<UUID, Integer>> totalDeathCountOnServers(UUID playerUUID) {
|
||||
String sql = "SELECT SUM(" + SessionsTable.DEATHS + ") as death_count, " +
|
||||
SessionsTable.SERVER_UUID + FROM + SessionsTable.TABLE_NAME +
|
||||
WHERE + SessionsTable.USER_UUID + "=?" +
|
||||
GROUP_BY + SessionsTable.SERVER_UUID;
|
||||
return new QueryStatement<Map<UUID, Integer>>(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, playerUUID.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<UUID, Integer> processResults(ResultSet set) throws SQLException {
|
||||
Map<UUID, Integer> killCountMap = new HashMap<>();
|
||||
while (set.next()) {
|
||||
UUID serverUUID = UUID.fromString(set.getString(SessionsTable.SERVER_UUID));
|
||||
int lastSeen = set.getInt("death_count");
|
||||
killCountMap.put(serverUUID, lastSeen);
|
||||
}
|
||||
return killCountMap;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* 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.db.access.queries;
|
||||
|
||||
import com.djrapitops.plan.db.access.HasMoreThanZeroQueryStatement;
|
||||
import com.djrapitops.plan.db.access.Query;
|
||||
import com.djrapitops.plan.db.access.QueryStatement;
|
||||
import com.djrapitops.plan.db.sql.tables.UserInfoTable;
|
||||
import com.djrapitops.plan.db.sql.tables.UsersTable;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.djrapitops.plan.db.sql.parsing.Sql.*;
|
||||
|
||||
/**
|
||||
* Static method class for queries that return information related to a single player.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class PlayerFetchQueries {
|
||||
|
||||
private PlayerFetchQueries() {
|
||||
/* static method class */
|
||||
}
|
||||
|
||||
/**
|
||||
* Query Player's name by player's UUID.
|
||||
*
|
||||
* @param playerUUID UUID of the player.
|
||||
* @return Optional, Name if found.
|
||||
*/
|
||||
public static Query<Optional<String>> playerUserName(UUID playerUUID) {
|
||||
String sql = "SELECT " + UsersTable.USER_NAME +
|
||||
FROM + UsersTable.TABLE_NAME +
|
||||
WHERE + UsersTable.USER_UUID + "=?";
|
||||
return new QueryStatement<Optional<String>>(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, playerUUID.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> processResults(ResultSet set) throws SQLException {
|
||||
if (set.next()) {
|
||||
return Optional.of(set.getString(UsersTable.USER_NAME));
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the player's BaseUser is registered.
|
||||
*
|
||||
* @param playerUUID UUID of the player.
|
||||
* @return True if the player's BaseUser is found
|
||||
*/
|
||||
public static Query<Boolean> isPlayerRegistered(UUID playerUUID) {
|
||||
String sql = "SELECT COUNT(1) as c FROM " + UsersTable.TABLE_NAME +
|
||||
WHERE + UsersTable.USER_UUID + "=?";
|
||||
return new HasMoreThanZeroQueryStatement(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, playerUUID.toString());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the player's UserInfo is registered.
|
||||
*
|
||||
* @param playerUUID UUID of the player.
|
||||
* @param serverUUID UUID of the Plan server.
|
||||
* @return True if the player's UserInfo is found
|
||||
*/
|
||||
public static Query<Boolean> isPlayerRegisteredOnServer(UUID playerUUID, UUID serverUUID) {
|
||||
String sql = "SELECT COUNT(1) as c FROM " + UserInfoTable.TABLE_NAME +
|
||||
WHERE + UserInfoTable.USER_UUID + "=?" +
|
||||
AND + UserInfoTable.SERVER_UUID + "=?";
|
||||
return new HasMoreThanZeroQueryStatement(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, playerUUID.toString());
|
||||
statement.setString(2, serverUUID.toString());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,163 @@
|
||||
/*
|
||||
* 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.db.access.queries;
|
||||
|
||||
import com.djrapitops.plan.db.access.Query;
|
||||
import com.djrapitops.plan.db.access.QueryAllStatement;
|
||||
import com.djrapitops.plan.db.access.QueryStatement;
|
||||
import com.djrapitops.plan.db.sql.tables.*;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.djrapitops.plan.db.sql.parsing.Sql.*;
|
||||
|
||||
/**
|
||||
* Static method class for queries that count how many entries of particular kinds there are for a server.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class ServerAggregateQueries {
|
||||
|
||||
private ServerAggregateQueries() {
|
||||
/* Static method class */
|
||||
}
|
||||
|
||||
/**
|
||||
* Count how many users are in the Plan database.
|
||||
*
|
||||
* @return Count of base users, all users in a network after Plan installation.
|
||||
*/
|
||||
public static Query<Integer> baseUserCount() {
|
||||
String sql = "SELECT COUNT(1) as c FROM " + UsersTable.TABLE_NAME;
|
||||
return new QueryAllStatement<Integer>(sql) {
|
||||
@Override
|
||||
public Integer processResults(ResultSet set) throws SQLException {
|
||||
return set.next() ? set.getInt("c") : 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Count how many users are on a server in the network.
|
||||
*
|
||||
* @param serverUUID ServerUUID of the Plan server.
|
||||
* @return Count of users registered to that server after Plan installation.
|
||||
*/
|
||||
public static Query<Integer> serverUserCount(UUID serverUUID) {
|
||||
String sql = "SELECT COUNT(1) as c FROM " + UserInfoTable.TABLE_NAME +
|
||||
WHERE + UserInfoTable.SERVER_UUID + "=?";
|
||||
return new QueryStatement<Integer>(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, serverUUID.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer processResults(ResultSet set) throws SQLException {
|
||||
return set.next() ? set.getInt("c") : 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Count how many users are on each server in the network.
|
||||
* <p>
|
||||
* Please note that counts can overlap as one user can join multiple servers.
|
||||
* Use {@link ServerAggregateQueries#baseUserCount()} if you want to count total number of users.
|
||||
*
|
||||
* @return Map: Server UUID - Count of users registered to that server
|
||||
*/
|
||||
public static Query<Map<UUID, Integer>> serverUserCounts() {
|
||||
String sql = "SELECT COUNT(1) as c, " + UserInfoTable.SERVER_UUID + FROM + UserInfoTable.TABLE_NAME +
|
||||
GROUP_BY + UserInfoTable.SERVER_UUID;
|
||||
return new QueryAllStatement<Map<UUID, Integer>>(sql, 100) {
|
||||
@Override
|
||||
public Map<UUID, Integer> processResults(ResultSet set) throws SQLException {
|
||||
Map<UUID, Integer> ofServer = new HashMap<>();
|
||||
while (set.next()) {
|
||||
UUID serverUUID = UUID.fromString(set.getString(UserInfoTable.SERVER_UUID));
|
||||
int count = set.getInt("c");
|
||||
ofServer.put(serverUUID, count);
|
||||
}
|
||||
return ofServer;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Count how many times commands have been used on a server.
|
||||
*
|
||||
* @param serverUUID Server UUID of the Plan server.
|
||||
* @return Map: Lowercase used command - Count of use times.
|
||||
*/
|
||||
public static Query<Map<String, Integer>> commandUsageCounts(UUID serverUUID) {
|
||||
String sql = SELECT + CommandUseTable.COMMAND + ", " + CommandUseTable.TIMES_USED + FROM + CommandUseTable.TABLE_NAME +
|
||||
WHERE + CommandUseTable.SERVER_ID + "=" + ServerTable.STATEMENT_SELECT_SERVER_ID;
|
||||
|
||||
return new QueryStatement<Map<String, Integer>>(sql, 5000) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, serverUUID.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Integer> processResults(ResultSet set) throws SQLException {
|
||||
Map<String, Integer> commandUse = new HashMap<>();
|
||||
while (set.next()) {
|
||||
String cmd = set.getString(CommandUseTable.COMMAND).toLowerCase();
|
||||
int amountUsed = set.getInt(CommandUseTable.TIMES_USED);
|
||||
commandUse.put(cmd, amountUsed);
|
||||
}
|
||||
return commandUse;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Query<Map<String, Integer>> networkGeolocationCounts() {
|
||||
String subQuery1 = SELECT +
|
||||
GeoInfoTable.USER_UUID + ", " +
|
||||
GeoInfoTable.GEOLOCATION + ", " +
|
||||
GeoInfoTable.LAST_USED +
|
||||
FROM + GeoInfoTable.TABLE_NAME;
|
||||
String subQuery2 = SELECT +
|
||||
GeoInfoTable.USER_UUID + ", " +
|
||||
"MAX(" + GeoInfoTable.LAST_USED + ") as m" +
|
||||
FROM + GeoInfoTable.TABLE_NAME +
|
||||
GROUP_BY + GeoInfoTable.USER_UUID;
|
||||
String sql = SELECT + GeoInfoTable.GEOLOCATION + ", COUNT(1) as c FROM (" +
|
||||
"(" + subQuery1 + ") AS q1" +
|
||||
" INNER JOIN (" + subQuery2 + ") AS q2 ON q1.uuid = q2.uuid)" +
|
||||
WHERE + GeoInfoTable.LAST_USED + "=m" +
|
||||
GROUP_BY + GeoInfoTable.GEOLOCATION;
|
||||
|
||||
return new QueryAllStatement<Map<String, Integer>>(sql) {
|
||||
@Override
|
||||
public Map<String, Integer> processResults(ResultSet set) throws SQLException {
|
||||
Map<String, Integer> geolocationCounts = new HashMap<>();
|
||||
while (set.next()) {
|
||||
geolocationCounts.put(set.getString(GeoInfoTable.GEOLOCATION), set.getInt("c"));
|
||||
}
|
||||
return geolocationCounts;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,173 @@
|
||||
/*
|
||||
* 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.db.access.queries.containers;
|
||||
|
||||
import com.djrapitops.plan.data.container.*;
|
||||
import com.djrapitops.plan.data.store.containers.DataContainer;
|
||||
import com.djrapitops.plan.data.store.containers.PerServerContainer;
|
||||
import com.djrapitops.plan.data.store.containers.PlayerContainer;
|
||||
import com.djrapitops.plan.data.store.containers.SupplierDataContainer;
|
||||
import com.djrapitops.plan.data.store.keys.PerServerKeys;
|
||||
import com.djrapitops.plan.data.store.keys.PlayerKeys;
|
||||
import com.djrapitops.plan.data.store.mutators.PerServerMutator;
|
||||
import com.djrapitops.plan.data.store.mutators.SessionsMutator;
|
||||
import com.djrapitops.plan.data.store.objects.Nickname;
|
||||
import com.djrapitops.plan.db.SQLDB;
|
||||
import com.djrapitops.plan.db.access.Query;
|
||||
import com.djrapitops.plan.db.access.queries.objects.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Used to get PlayerContainers of all players on the network, some limitations apply to DataContainer keys.
|
||||
* <p>
|
||||
* Limitations:
|
||||
* - PlayerContainers do not support: PlayerKeys WORLD_TIMES, PLAYER_KILLS, PLAYER_KILL_COUNT
|
||||
* - PlayerContainers PlayerKeys.PER_SERVER does not support: PerServerKeys WORLD_TIMES, PLAYER_KILLS, PLAYER_KILL_COUNT
|
||||
* <p>
|
||||
* Blocking methods are not called until DataContainer getter methods are called.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class AllPlayerContainersQuery implements Query<List<PlayerContainer>> {
|
||||
|
||||
/**
|
||||
* Create PerServerContainers for each player.
|
||||
*
|
||||
* @param sessions Map: Server UUID - Map: Player UUID - List of Sessions
|
||||
* @param allUserInfo Map: Server UUID - List of Users
|
||||
* @param allPings Map: Player UUID - List of Ping data
|
||||
* @return Map: Player UUID - PerServerContainer
|
||||
*/
|
||||
private Map<UUID, PerServerContainer> getPerServerData(
|
||||
Map<UUID, Map<UUID, List<Session>>> sessions,
|
||||
Map<UUID, List<UserInfo>> allUserInfo,
|
||||
Map<UUID, List<Ping>> allPings
|
||||
) {
|
||||
Map<UUID, PerServerContainer> perServerContainers = new HashMap<>();
|
||||
|
||||
for (Map.Entry<UUID, List<UserInfo>> entry : allUserInfo.entrySet()) {
|
||||
UUID serverUUID = entry.getKey();
|
||||
List<UserInfo> serverUserInfo = entry.getValue();
|
||||
|
||||
for (UserInfo userInfo : serverUserInfo) {
|
||||
UUID uuid = userInfo.getPlayerUuid();
|
||||
if (uuid == null) {
|
||||
continue;
|
||||
}
|
||||
PerServerContainer perServerContainer = perServerContainers.getOrDefault(uuid, new PerServerContainer());
|
||||
DataContainer container = perServerContainer.getOrDefault(serverUUID, new SupplierDataContainer());
|
||||
container.putRawData(PlayerKeys.REGISTERED, userInfo.getRegistered());
|
||||
container.putRawData(PlayerKeys.BANNED, userInfo.isBanned());
|
||||
container.putRawData(PlayerKeys.OPERATOR, userInfo.isOperator());
|
||||
perServerContainer.put(serverUUID, container);
|
||||
perServerContainers.put(uuid, perServerContainer);
|
||||
}
|
||||
}
|
||||
|
||||
for (Map.Entry<UUID, Map<UUID, List<Session>>> entry : sessions.entrySet()) {
|
||||
UUID serverUUID = entry.getKey();
|
||||
Map<UUID, List<Session>> serverUserSessions = entry.getValue();
|
||||
|
||||
for (Map.Entry<UUID, List<Session>> sessionEntry : serverUserSessions.entrySet()) {
|
||||
UUID playerUUID = sessionEntry.getKey();
|
||||
PerServerContainer perServerContainer = perServerContainers.getOrDefault(playerUUID, new PerServerContainer());
|
||||
DataContainer container = perServerContainer.getOrDefault(serverUUID, new SupplierDataContainer());
|
||||
|
||||
List<Session> serverSessions = sessionEntry.getValue();
|
||||
container.putRawData(PerServerKeys.SESSIONS, serverSessions);
|
||||
|
||||
container.putSupplier(PerServerKeys.LAST_SEEN, () -> SessionsMutator.forContainer(container).toLastSeen());
|
||||
|
||||
container.putSupplier(PerServerKeys.WORLD_TIMES, () -> SessionsMutator.forContainer(container).toTotalWorldTimes());
|
||||
container.putSupplier(PerServerKeys.PLAYER_DEATHS, () -> SessionsMutator.forContainer(container).toPlayerDeathList());
|
||||
container.putSupplier(PerServerKeys.PLAYER_KILLS, () -> SessionsMutator.forContainer(container).toPlayerKillList());
|
||||
container.putSupplier(PerServerKeys.PLAYER_KILL_COUNT, () -> container.getUnsafe(PerServerKeys.PLAYER_KILLS).size());
|
||||
container.putSupplier(PerServerKeys.MOB_KILL_COUNT, () -> SessionsMutator.forContainer(container).toMobKillCount());
|
||||
container.putSupplier(PerServerKeys.DEATH_COUNT, () -> SessionsMutator.forContainer(container).toDeathCount());
|
||||
container.putSupplier(PerServerKeys.MOB_DEATH_COUNT, () ->
|
||||
container.getUnsafe(PerServerKeys.DEATH_COUNT) - container.getUnsafe(PerServerKeys.PLAYER_DEATH_COUNT)
|
||||
);
|
||||
perServerContainer.put(serverUUID, container);
|
||||
perServerContainers.put(playerUUID, perServerContainer);
|
||||
}
|
||||
}
|
||||
|
||||
for (Map.Entry<UUID, List<Ping>> entry : allPings.entrySet()) {
|
||||
UUID uuid = entry.getKey();
|
||||
for (Ping ping : entry.getValue()) {
|
||||
UUID serverUUID = ping.getServerUUID();
|
||||
PerServerContainer perServerContainer = perServerContainers.getOrDefault(uuid, new PerServerContainer());
|
||||
DataContainer container = perServerContainer.getOrDefault(serverUUID, new SupplierDataContainer());
|
||||
|
||||
if (!container.supports(PerServerKeys.PING)) {
|
||||
container.putRawData(PerServerKeys.PING, new ArrayList<>());
|
||||
}
|
||||
container.getUnsafe(PerServerKeys.PING).add(ping);
|
||||
|
||||
perServerContainer.put(serverUUID, container);
|
||||
perServerContainers.put(uuid, perServerContainer);
|
||||
}
|
||||
}
|
||||
|
||||
return perServerContainers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PlayerContainer> executeQuery(SQLDB db) {
|
||||
List<PlayerContainer> containers = new ArrayList<>();
|
||||
|
||||
Collection<BaseUser> users = db.query(BaseUserQueries.fetchAllBaseUsers());
|
||||
Map<UUID, List<GeoInfo>> geoInfo = db.query(GeoInfoQueries.fetchAllGeoInformation());
|
||||
Map<UUID, List<Ping>> allPings = db.query(PingQueries.fetchAllPingData());
|
||||
Map<UUID, List<Nickname>> allNicknames = db.query(NicknameQueries.fetchAllNicknameDataByPlayerUUIDs());
|
||||
|
||||
Map<UUID, Map<UUID, List<Session>>> sessions = db.query(SessionQueries.fetchAllSessionsWithoutKillOrWorldData());
|
||||
Map<UUID, List<UserInfo>> allUserInfo = db.query(UserInfoQueries.fetchAllUserInformation());
|
||||
Map<UUID, PerServerContainer> perServerInfo = getPerServerData(sessions, allUserInfo, allPings);
|
||||
|
||||
for (BaseUser baseUser : users) {
|
||||
PlayerContainer container = new PlayerContainer();
|
||||
UUID uuid = baseUser.getUuid();
|
||||
container.putRawData(PlayerKeys.UUID, uuid);
|
||||
|
||||
container.putRawData(PlayerKeys.REGISTERED, baseUser.getRegistered());
|
||||
container.putRawData(PlayerKeys.NAME, baseUser.getName());
|
||||
container.putRawData(PlayerKeys.KICK_COUNT, baseUser.getTimesKicked());
|
||||
container.putRawData(PlayerKeys.GEO_INFO, geoInfo.get(uuid));
|
||||
container.putRawData(PlayerKeys.PING, allPings.get(uuid));
|
||||
container.putRawData(PlayerKeys.NICKNAMES, allNicknames.get(uuid));
|
||||
container.putRawData(PlayerKeys.PER_SERVER, perServerInfo.get(uuid));
|
||||
|
||||
container.putCachingSupplier(PlayerKeys.SESSIONS, () -> {
|
||||
List<Session> playerSessions = PerServerMutator.forContainer(container).flatMapSessions();
|
||||
container.getValue(PlayerKeys.ACTIVE_SESSION).ifPresent(playerSessions::add);
|
||||
return playerSessions;
|
||||
}
|
||||
);
|
||||
|
||||
// Calculating getters
|
||||
container.putSupplier(PlayerKeys.LAST_SEEN, () -> SessionsMutator.forContainer(container).toLastSeen());
|
||||
|
||||
container.putSupplier(PlayerKeys.MOB_KILL_COUNT, () -> SessionsMutator.forContainer(container).toMobKillCount());
|
||||
container.putSupplier(PlayerKeys.DEATH_COUNT, () -> SessionsMutator.forContainer(container).toDeathCount());
|
||||
|
||||
containers.add(container);
|
||||
}
|
||||
return containers;
|
||||
}
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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.db.access.queries.containers;
|
||||
|
||||
import com.djrapitops.plan.data.store.containers.NetworkContainer;
|
||||
import com.djrapitops.plan.data.store.containers.PlayerContainer;
|
||||
import com.djrapitops.plan.data.store.containers.ServerContainer;
|
||||
import com.djrapitops.plan.db.access.Query;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Static method class for queries that return some kind of {@link com.djrapitops.plan.data.store.containers.DataContainer}.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class ContainerFetchQueries {
|
||||
|
||||
private ContainerFetchQueries() {
|
||||
/* Static method class */
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to get a NetworkContainer, some limitations apply to values returned by DataContainer keys.
|
||||
*
|
||||
* @return a new NetworkContainer.
|
||||
* @see NetworkContainerQuery
|
||||
*/
|
||||
public static Query<NetworkContainer> fetchNetworkContainer() {
|
||||
return new NetworkContainerQuery();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to get a ServerContainer, some limitations apply to values returned by DataContainer keys.
|
||||
*
|
||||
* @param serverUUID UUID of the Server.
|
||||
* @return a new ServerContainer.
|
||||
* @see ServerContainerQuery
|
||||
*/
|
||||
public static Query<ServerContainer> fetchServerContainer(UUID serverUUID) {
|
||||
return new ServerContainerQuery(serverUUID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to get a PlayerContainer of a specific player.
|
||||
* <p>
|
||||
* Blocking methods are not called until DataContainer getter methods are called.
|
||||
*
|
||||
* @param playerUUID UUID of the player.
|
||||
* @return a new PlayerContainer.
|
||||
* @see PlayerContainerQuery
|
||||
*/
|
||||
public static Query<PlayerContainer> fetchPlayerContainer(UUID playerUUID) {
|
||||
return new PlayerContainerQuery(playerUUID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to get PlayerContainers of all players on the network, some limitations apply to DataContainer keys.
|
||||
* <p>
|
||||
* Limitations:
|
||||
* - PlayerContainers do not support: PlayerKeys WORLD_TIMES, PLAYER_KILLS, PLAYER_KILL_COUNT
|
||||
* - PlayerContainers PlayerKeys.PER_SERVER does not support: PerServerKeys WORLD_TIMES, PLAYER_KILLS, PLAYER_KILL_COUNT
|
||||
* <p>
|
||||
* Blocking methods are not called until DataContainer getter methods are called.
|
||||
*
|
||||
* @return a list of PlayerContainers in Plan database.
|
||||
*/
|
||||
public static Query<List<PlayerContainer>> fetchAllPlayerContainers() {
|
||||
return new AllPlayerContainersQuery();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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.db.access.queries.containers;
|
||||
|
||||
import com.djrapitops.plan.data.store.containers.NetworkContainer;
|
||||
import com.djrapitops.plan.data.store.containers.ServerContainer;
|
||||
import com.djrapitops.plan.data.store.keys.NetworkKeys;
|
||||
import com.djrapitops.plan.data.store.keys.ServerKeys;
|
||||
import com.djrapitops.plan.db.SQLDB;
|
||||
import com.djrapitops.plan.db.access.Query;
|
||||
import com.djrapitops.plan.db.access.queries.objects.ServerQueries;
|
||||
import com.djrapitops.plan.db.access.queries.objects.TPSQueries;
|
||||
import com.djrapitops.plan.system.info.server.Server;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Used to get a NetworkContainer, some limitations apply to values returned by DataContainer keys.
|
||||
* <p>
|
||||
* Limitations:
|
||||
* - Bungee ServerContainer does not support: ServerKeys WORLD_TIMES, PLAYER_KILLS, PLAYER_DEATHS, PLAYER_KILL_COUNT
|
||||
* - Bungee ServerContainer ServerKeys.TPS only contains playersOnline values
|
||||
* - NetworkKeys.PLAYERS PlayerContainers:
|
||||
* - do not support: PlayerKeys WORLD_TIMES, PLAYER_KILLS, PLAYER_DEATHS, PLAYER_KILL_COUNT
|
||||
* - PlayerKeys.PER_SERVER does not support: PerServerKeys WORLD_TIMES, PLAYER_KILLS, PLAYER_DEATHS, PLAYER_KILL_COUNT
|
||||
* <p>
|
||||
* Blocking methods are not called until DataContainer getter methods are called.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class NetworkContainerQuery implements Query<NetworkContainer> {
|
||||
|
||||
private static Query<ServerContainer> getProxyServerContainer() {
|
||||
return db -> {
|
||||
Optional<Server> proxyInformation = db.query(ServerQueries.fetchProxyServerInformation());
|
||||
if (!proxyInformation.isPresent()) {
|
||||
return new ServerContainer();
|
||||
}
|
||||
|
||||
UUID proxyUUID = proxyInformation.get().getUuid();
|
||||
ServerContainer container = db.query(ContainerFetchQueries.fetchServerContainer(proxyUUID));
|
||||
container.putCachingSupplier(ServerKeys.PLAYERS, () -> db.query(ContainerFetchQueries.fetchAllPlayerContainers()));
|
||||
container.putCachingSupplier(ServerKeys.TPS, () -> db.query(TPSQueries.fetchTPSDataOfServer(proxyUUID)));
|
||||
container.putSupplier(ServerKeys.WORLD_TIMES, null); // Additional Session information not supported
|
||||
container.putSupplier(ServerKeys.PLAYER_KILLS, null);
|
||||
container.putSupplier(ServerKeys.PLAYER_KILL_COUNT, null);
|
||||
|
||||
return container;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public NetworkContainer executeQuery(SQLDB db) {
|
||||
ServerContainer bungeeContainer = db.query(getProxyServerContainer());
|
||||
NetworkContainer networkContainer = db.getNetworkContainerFactory().forBungeeContainer(bungeeContainer);
|
||||
networkContainer.putCachingSupplier(NetworkKeys.BUKKIT_SERVERS, () ->
|
||||
db.query(ServerQueries.fetchPlanServerInformation()).values()
|
||||
.stream().filter(Server::isNotProxy).collect(Collectors.toSet())
|
||||
);
|
||||
return networkContainer;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user