mirror of
https://github.com/plan-player-analytics/Plan.git
synced 2024-09-28 22:47:38 +02:00
Merge pull request #1683 from plan-player-analytics/version-5.2
Version 5.2
This commit is contained in:
commit
103649dcf5
@ -3,7 +3,8 @@ plugins {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly group: 'org.apache.commons', name: 'commons-lang3', version: '3.11'
|
||||
compileOnly "org.apache.commons:commons-text:$commonsTextVersion"
|
||||
testCompile "org.apache.commons:commons-text:$commonsTextVersion"
|
||||
compileOnly "com.google.code.gson:gson:$gsonVersion"
|
||||
}
|
||||
|
||||
|
@ -22,8 +22,9 @@ import com.djrapitops.plan.extension.icon.Icon;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Object for giving Plan table data.
|
||||
@ -186,7 +187,17 @@ public final class Table {
|
||||
return this; // Ignore row when all values are null or no values are present.
|
||||
}
|
||||
|
||||
building.rows.add(Arrays.copyOf(values, 5));
|
||||
Object[] row = new Object[5];
|
||||
|
||||
for (int i = 0; i < Math.min(values.length, 5); i++) {
|
||||
Object value = values[i];
|
||||
if (value instanceof Optional) {
|
||||
value = ((Optional<?>) value).map(Objects::toString).orElse("-");
|
||||
}
|
||||
row[i] = value;
|
||||
}
|
||||
|
||||
building.rows.add(row);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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.extension.table;
|
||||
|
||||
import com.djrapitops.plan.extension.icon.Icon;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
class TableTest {
|
||||
|
||||
@Test
|
||||
void tableWithVaryingRowLengthsHasNoErrors() {
|
||||
Table.Factory table = Table.builder()
|
||||
.columnOne("", Icon.called("").build())
|
||||
.columnTwo("", Icon.called("").build())
|
||||
.columnThree("", Icon.called("").build())
|
||||
.columnFour("", Icon.called("").build())
|
||||
.columnFive("", Icon.called("").build());
|
||||
|
||||
table.addRow();
|
||||
table.addRow("a");
|
||||
table.addRow("a", "b");
|
||||
table.addRow("a");
|
||||
table.addRow("a", "b", "c", "d", "e", "f");
|
||||
table.addRow("a", "b", "c", "d");
|
||||
|
||||
List<Object[]> expected = Arrays.asList(
|
||||
new Object[]{"a", null, null, null, null},
|
||||
new Object[]{"a", "b", null, null, null},
|
||||
new Object[]{"a", null, null, null, null},
|
||||
new Object[]{"a", "b", "c", "d", "e"},
|
||||
new Object[]{"a", "b", "c", "d", null}
|
||||
);
|
||||
List<Object[]> result = table.build().getRows();
|
||||
|
||||
for (int i = 0; i < expected.size(); i++) {
|
||||
assertArrayEquals(expected.get(i), result.get(i));
|
||||
}
|
||||
assertEquals(expected.size(), result.size());
|
||||
}
|
||||
|
||||
}
|
@ -33,10 +33,10 @@ allprojects {
|
||||
wrapper.gradleVersion = "6.2.1"
|
||||
|
||||
group "com.djrapitops"
|
||||
version "5.1-SNAPSHOT"
|
||||
version "5.2-SNAPSHOT"
|
||||
|
||||
ext.majorVersion = '5'
|
||||
ext.minorVersion = '1'
|
||||
ext.minorVersion = '2'
|
||||
ext.buildVersion = buildVersion
|
||||
ext.fullVersion = project.ext.majorVersion + '.' + project.ext.minorVersion + ' build ' + project.ext.buildVersion
|
||||
|
||||
@ -84,6 +84,7 @@ subprojects {
|
||||
ext.caffeineVersion = "2.8.0"
|
||||
ext.h2Version = "1.4.199"
|
||||
ext.mysqlVersion = "8.0.22"
|
||||
ext.sqliteVersion = "3.34.0"
|
||||
ext.hikariVersion = "3.4.5"
|
||||
ext.slf4jVersion = "1.7.30"
|
||||
ext.geoIpVersion = "2.15.0"
|
||||
@ -140,7 +141,7 @@ subprojects {
|
||||
testCompile "com.jayway.awaitility:awaitility:1.7.0" // Awaitility (Concurrent wait conditions)
|
||||
|
||||
// Testing dependencies required by Plan
|
||||
testCompile "org.xerial:sqlite-jdbc:3.34.0" // SQLite
|
||||
testCompile "org.xerial:sqlite-jdbc:$sqliteVersion" // SQLite
|
||||
testCompile "mysql:mysql-connector-java:$mysqlVersion" // MySQL
|
||||
}
|
||||
|
||||
|
@ -1,154 +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;
|
||||
|
||||
import com.djrapitops.plan.delivery.webserver.cache.JSONCache;
|
||||
import com.djrapitops.plan.extension.ExtensionServerMethodCallerTask;
|
||||
import com.djrapitops.plan.gathering.ShutdownHook;
|
||||
import com.djrapitops.plan.gathering.timed.BukkitPingCounter;
|
||||
import com.djrapitops.plan.gathering.timed.ServerTPSCounter;
|
||||
import com.djrapitops.plan.gathering.timed.SystemUsageBuffer;
|
||||
import com.djrapitops.plan.gathering.timed.TPSCounter;
|
||||
import com.djrapitops.plan.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.settings.config.paths.DataGatheringSettings;
|
||||
import com.djrapitops.plan.settings.config.paths.TimeSettings;
|
||||
import com.djrapitops.plan.settings.upkeep.ConfigStoreTask;
|
||||
import com.djrapitops.plan.storage.upkeep.DBCleanTask;
|
||||
import com.djrapitops.plan.storage.upkeep.LogsFolderCleanTask;
|
||||
import com.djrapitops.plugin.api.TimeAmount;
|
||||
import com.djrapitops.plugin.task.RunnableFactory;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* TaskSystem responsible for registering tasks for Bukkit.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Singleton
|
||||
public class BukkitTaskSystem extends TaskSystem {
|
||||
|
||||
private final Plan plugin;
|
||||
private final PlanConfig config;
|
||||
private final ShutdownHook shutdownHook;
|
||||
private final JSONCache.CleanTask jsonCacheCleanTask;
|
||||
private final LogsFolderCleanTask logsFolderCleanTask;
|
||||
private final BukkitPingCounter pingCounter;
|
||||
private final ConfigStoreTask configStoreTask;
|
||||
private final DBCleanTask dbCleanTask;
|
||||
private final ExtensionServerMethodCallerTask extensionServerMethodCallerTask;
|
||||
private final TPSCounter tpsCounter;
|
||||
private final SystemUsageBuffer.RamAndCpuTask ramAndCpuTask;
|
||||
private final SystemUsageBuffer.DiskTask diskTask;
|
||||
|
||||
@Inject
|
||||
public BukkitTaskSystem(
|
||||
Plan plugin,
|
||||
PlanConfig config,
|
||||
ShutdownHook shutdownHook,
|
||||
RunnableFactory runnableFactory,
|
||||
|
||||
ServerTPSCounter<World> tpsCounter,
|
||||
BukkitPingCounter pingCounter,
|
||||
ExtensionServerMethodCallerTask extensionServerMethodCallerTask,
|
||||
|
||||
LogsFolderCleanTask logsFolderCleanTask,
|
||||
ConfigStoreTask configStoreTask,
|
||||
DBCleanTask dbCleanTask,
|
||||
JSONCache.CleanTask jsonCacheCleanTask,
|
||||
SystemUsageBuffer.RamAndCpuTask ramAndCpuTask,
|
||||
SystemUsageBuffer.DiskTask diskTask
|
||||
) {
|
||||
super(runnableFactory);
|
||||
this.plugin = plugin;
|
||||
this.config = config;
|
||||
this.shutdownHook = shutdownHook;
|
||||
this.jsonCacheCleanTask = jsonCacheCleanTask;
|
||||
|
||||
this.tpsCounter = tpsCounter;
|
||||
this.pingCounter = pingCounter;
|
||||
this.extensionServerMethodCallerTask = extensionServerMethodCallerTask;
|
||||
|
||||
this.logsFolderCleanTask = logsFolderCleanTask;
|
||||
this.configStoreTask = configStoreTask;
|
||||
this.dbCleanTask = dbCleanTask;
|
||||
this.ramAndCpuTask = ramAndCpuTask;
|
||||
this.diskTask = diskTask;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enable() {
|
||||
registerTPSCounter();
|
||||
registerPingCounter();
|
||||
registerExtensionDataGatheringTask();
|
||||
registerUpkeepTasks();
|
||||
|
||||
shutdownHook.register();
|
||||
}
|
||||
|
||||
private void registerUpkeepTasks() {
|
||||
// +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(configStoreTask).runTaskLaterAsynchronously(storeDelay);
|
||||
registerTask(logsFolderCleanTask).runTaskLaterAsynchronously(TimeAmount.toTicks(30L, TimeUnit.SECONDS));
|
||||
registerTask(dbCleanTask).runTaskTimerAsynchronously(
|
||||
TimeAmount.toTicks(20, TimeUnit.SECONDS),
|
||||
TimeAmount.toTicks(config.get(TimeSettings.CLEAN_DATABASE_PERIOD), TimeUnit.MILLISECONDS)
|
||||
);
|
||||
long minute = TimeAmount.toTicks(1, TimeUnit.MINUTES);
|
||||
registerTask(jsonCacheCleanTask).runTaskTimerAsynchronously(minute, minute);
|
||||
}
|
||||
|
||||
private void registerTPSCounter() {
|
||||
long halfSecondTicks = TimeAmount.toTicks(500L, TimeUnit.MILLISECONDS);
|
||||
long secondTicks = TimeAmount.toTicks(1L, TimeUnit.SECONDS);
|
||||
long minuteTicks = TimeAmount.toTicks(1L, TimeUnit.MINUTES);
|
||||
registerTask(tpsCounter).runTaskTimer(minuteTicks, secondTicks);
|
||||
registerTask(ramAndCpuTask).runTaskTimerAsynchronously(minuteTicks - halfSecondTicks, secondTicks);
|
||||
registerTask(diskTask).runTaskTimerAsynchronously(50L * secondTicks, minuteTicks);
|
||||
}
|
||||
|
||||
private void registerPingCounter() {
|
||||
try {
|
||||
Long pingDelay = config.get(TimeSettings.PING_SERVER_ENABLE_DELAY);
|
||||
if (pingDelay < TimeUnit.HOURS.toMillis(1L) && config.isTrue(DataGatheringSettings.PING)) {
|
||||
plugin.registerListener(pingCounter);
|
||||
long startDelay = TimeAmount.toTicks(pingDelay, TimeUnit.MILLISECONDS);
|
||||
registerTask(pingCounter).runTaskTimer(startDelay, 40L);
|
||||
}
|
||||
} catch (ExceptionInInitializerError | NoClassDefFoundError ignore) {
|
||||
// Running CraftBukkit
|
||||
}
|
||||
}
|
||||
|
||||
private void registerExtensionDataGatheringTask() {
|
||||
long extensionRefreshPeriod = TimeAmount.toTicks(config.get(TimeSettings.EXTENSION_DATA_REFRESH_PERIOD), TimeUnit.MILLISECONDS);
|
||||
registerTask(extensionServerMethodCallerTask).runTaskTimerAsynchronously(
|
||||
TimeAmount.toTicks(30, TimeUnit.SECONDS), extensionRefreshPeriod
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disable() {
|
||||
super.disable();
|
||||
Bukkit.getScheduler().cancelTasks(plugin);
|
||||
}
|
||||
}
|
@ -120,16 +120,19 @@ public class Plan extends BukkitPlugin implements PlanPlugin {
|
||||
*/
|
||||
@Override
|
||||
public void onDisable() {
|
||||
if (serverShutdownSave != null) {
|
||||
serverShutdownSave.performSave();
|
||||
}
|
||||
if (system != null) {
|
||||
system.disable();
|
||||
}
|
||||
if (serverShutdownSave != null) serverShutdownSave.performSave();
|
||||
cancelAllTasks();
|
||||
if (system != null) system.disable();
|
||||
|
||||
logger.info(locale != null ? locale.getString(PluginLang.DISABLED) : PluginLang.DISABLED.getDefault());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelAllTasks() {
|
||||
runnableFactory.cancelAllKnownTasks();
|
||||
Bukkit.getScheduler().cancelTasks(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersion() {
|
||||
return getDescription().getVersion();
|
||||
|
@ -26,6 +26,7 @@ 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;
|
||||
import com.djrapitops.plan.modules.bukkit.BukkitTaskModule;
|
||||
import dagger.BindsInstance;
|
||||
import dagger.Component;
|
||||
|
||||
@ -45,7 +46,8 @@ import javax.inject.Singleton;
|
||||
|
||||
ServerCommandModule.class,
|
||||
BukkitServerPropertiesModule.class,
|
||||
BukkitSuperClassBindingModule.class
|
||||
BukkitSuperClassBindingModule.class,
|
||||
BukkitTaskModule.class
|
||||
})
|
||||
public interface PlanBukkitComponent {
|
||||
|
||||
|
@ -52,7 +52,7 @@ class BukkitPartBuilder implements MessageBuilder {
|
||||
try {
|
||||
nextPart.part.appendLegacy(text);
|
||||
} catch (NoSuchMethodError oldVersion) { // not supported in 1.8
|
||||
nextPart.part.append(ChatColor.translateAlternateColorCodes('§', text));
|
||||
nextPart.part.append(ChatColor.translateAlternateColorCodes('\u00a7', text));
|
||||
}
|
||||
return nextPart;
|
||||
}
|
||||
|
@ -1,45 +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.gathering.importing;
|
||||
|
||||
import com.djrapitops.plan.gathering.importing.importers.OfflinePlayerImporter;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
/**
|
||||
* ImportSystem implementation for Bukkit.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Singleton
|
||||
public class BukkitImportSystem extends ImportSystem {
|
||||
|
||||
private final OfflinePlayerImporter offlinePlayerImporter;
|
||||
|
||||
@Inject
|
||||
public BukkitImportSystem(
|
||||
OfflinePlayerImporter offlinePlayerImporter
|
||||
) {
|
||||
this.offlinePlayerImporter = offlinePlayerImporter;
|
||||
}
|
||||
|
||||
@Override
|
||||
void registerImporters() {
|
||||
registerImporter(offlinePlayerImporter);
|
||||
}
|
||||
}
|
@ -23,9 +23,12 @@
|
||||
*/
|
||||
package com.djrapitops.plan.gathering.timed;
|
||||
|
||||
import com.djrapitops.plan.Plan;
|
||||
import com.djrapitops.plan.TaskSystem;
|
||||
import com.djrapitops.plan.delivery.domain.DateObj;
|
||||
import com.djrapitops.plan.identification.ServerInfo;
|
||||
import com.djrapitops.plan.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.settings.config.paths.DataGatheringSettings;
|
||||
import com.djrapitops.plan.settings.config.paths.TimeSettings;
|
||||
import com.djrapitops.plan.storage.database.DBSystem;
|
||||
import com.djrapitops.plan.storage.database.transactions.events.PingStoreTransaction;
|
||||
@ -60,7 +63,7 @@ import java.util.logging.Logger;
|
||||
* @author games647
|
||||
*/
|
||||
@Singleton
|
||||
public class BukkitPingCounter extends AbsRunnable implements Listener {
|
||||
public class BukkitPingCounter extends TaskSystem.Task implements Listener {
|
||||
|
||||
//the server is pinging the client every 40 Ticks (2 sec) - so check it then
|
||||
//https://github.com/bergerkiller/CraftSource/blob/master/net.minecraft.server/PlayerConnection.java#L178
|
||||
@ -70,13 +73,23 @@ public class BukkitPingCounter extends AbsRunnable implements Listener {
|
||||
private static MethodHandle PING_FIELD;
|
||||
private static MethodHandle GET_HANDLE_METHOD;
|
||||
|
||||
private final Map<UUID, List<DateObj<Integer>>> playerHistory;
|
||||
|
||||
private final Plan plugin;
|
||||
private final PlanConfig config;
|
||||
private final DBSystem dbSystem;
|
||||
private final ServerInfo serverInfo;
|
||||
private final RunnableFactory runnableFactory;
|
||||
|
||||
@Inject
|
||||
public BukkitPingCounter(
|
||||
Plan plugin,
|
||||
PlanConfig config,
|
||||
DBSystem dbSystem,
|
||||
ServerInfo serverInfo,
|
||||
RunnableFactory runnableFactory
|
||||
) {
|
||||
this.plugin = plugin;
|
||||
BukkitPingCounter.loadPingMethodDetails();
|
||||
this.config = config;
|
||||
this.dbSystem = dbSystem;
|
||||
@ -85,12 +98,6 @@ public class BukkitPingCounter extends AbsRunnable implements Listener {
|
||||
playerHistory = new HashMap<>();
|
||||
}
|
||||
|
||||
private final Map<UUID, List<DateObj<Integer>>> playerHistory;
|
||||
|
||||
private final PlanConfig config;
|
||||
private final DBSystem dbSystem;
|
||||
private final ServerInfo serverInfo;
|
||||
private final RunnableFactory runnableFactory;
|
||||
|
||||
private static void loadPingMethodDetails() {
|
||||
PING_METHOD_AVAILABLE = isPingMethodAvailable();
|
||||
@ -135,6 +142,17 @@ public class BukkitPingCounter extends AbsRunnable implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(RunnableFactory runnableFactory) {
|
||||
Long startDelay = config.get(TimeSettings.PING_SERVER_ENABLE_DELAY);
|
||||
if (startDelay < TimeUnit.HOURS.toMillis(1L) && config.isTrue(DataGatheringSettings.PING)) {
|
||||
plugin.registerListener(this);
|
||||
long delay = TimeAmount.toTicks(startDelay, TimeUnit.MILLISECONDS);
|
||||
long period = 40L;
|
||||
runnableFactory.create(null, this).runTaskTimer(delay, period);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
long time = System.currentTimeMillis();
|
||||
|
@ -18,8 +18,11 @@ package com.djrapitops.plan.modules.bukkit;
|
||||
|
||||
import com.djrapitops.plan.Plan;
|
||||
import com.djrapitops.plan.PlanPlugin;
|
||||
import com.djrapitops.plan.gathering.importing.importers.Importer;
|
||||
import com.djrapitops.plan.gathering.importing.importers.OfflinePlayerImporter;
|
||||
import dagger.Binds;
|
||||
import dagger.Module;
|
||||
import dagger.multibindings.IntoSet;
|
||||
|
||||
/**
|
||||
* Dagger module for binding Plan instance.
|
||||
@ -31,4 +34,8 @@ public interface BukkitPlanModule {
|
||||
|
||||
@Binds
|
||||
PlanPlugin bindPlanPlugin(Plan plugin);
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
Importer bindOfflinePlayerImporter(OfflinePlayerImporter importer);
|
||||
}
|
@ -17,13 +17,9 @@
|
||||
package com.djrapitops.plan.modules.bukkit;
|
||||
|
||||
import com.djrapitops.plan.BukkitServerShutdownSave;
|
||||
import com.djrapitops.plan.BukkitTaskSystem;
|
||||
import com.djrapitops.plan.TaskSystem;
|
||||
import com.djrapitops.plan.gathering.BukkitSensor;
|
||||
import com.djrapitops.plan.gathering.ServerSensor;
|
||||
import com.djrapitops.plan.gathering.ServerShutdownSave;
|
||||
import com.djrapitops.plan.gathering.importing.BukkitImportSystem;
|
||||
import com.djrapitops.plan.gathering.importing.ImportSystem;
|
||||
import com.djrapitops.plan.gathering.listeners.BukkitListenerSystem;
|
||||
import com.djrapitops.plan.gathering.listeners.ListenerSystem;
|
||||
import com.djrapitops.plan.identification.ServerInfo;
|
||||
@ -53,15 +49,9 @@ public interface BukkitSuperClassBindingModule {
|
||||
@Binds
|
||||
ConfigSystem bindConfigSystem(BukkitConfigSystem configSystem);
|
||||
|
||||
@Binds
|
||||
TaskSystem bindTaskSystem(BukkitTaskSystem taskSystem);
|
||||
|
||||
@Binds
|
||||
ListenerSystem bindListenerSystem(BukkitListenerSystem listenerSystem);
|
||||
|
||||
@Binds
|
||||
ImportSystem bindImportSystem(BukkitImportSystem importSystem);
|
||||
|
||||
@Binds
|
||||
ServerShutdownSave bindServerShutdownSave(BukkitServerShutdownSave shutdownSave);
|
||||
|
||||
|
@ -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.modules.bukkit;
|
||||
|
||||
import com.djrapitops.plan.TaskSystem;
|
||||
import com.djrapitops.plan.delivery.webserver.cache.JSONCache;
|
||||
import com.djrapitops.plan.extension.ExtensionServerDataUpdater;
|
||||
import com.djrapitops.plan.gathering.ShutdownHook;
|
||||
import com.djrapitops.plan.gathering.timed.BukkitPingCounter;
|
||||
import com.djrapitops.plan.gathering.timed.ServerTPSCounter;
|
||||
import com.djrapitops.plan.gathering.timed.SystemUsageBuffer;
|
||||
import com.djrapitops.plan.settings.upkeep.ConfigStoreTask;
|
||||
import com.djrapitops.plan.storage.upkeep.DBCleanTask;
|
||||
import com.djrapitops.plan.storage.upkeep.LogsFolderCleanTask;
|
||||
import dagger.Binds;
|
||||
import dagger.Module;
|
||||
import dagger.multibindings.IntoSet;
|
||||
import org.bukkit.World;
|
||||
|
||||
@Module
|
||||
public interface BukkitTaskModule {
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
TaskSystem.Task bindTPSCounter(ServerTPSCounter<World> tpsCounter);
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
TaskSystem.Task bindPingCounter(BukkitPingCounter pingCounter);
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
TaskSystem.Task bindExtensionServerDataUpdater(ExtensionServerDataUpdater extensionServerDataUpdater);
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
TaskSystem.Task bindLogCleanTask(LogsFolderCleanTask logsFolderCleanTask);
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
TaskSystem.Task bindConfigStoreTask(ConfigStoreTask configStoreTask);
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
TaskSystem.Task bindDBCleanTask(DBCleanTask cleanTask);
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
TaskSystem.Task bindJSONCacheCleanTask(JSONCache.CleanTask cleanTask);
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
TaskSystem.Task bindRamAndCpuTask(SystemUsageBuffer.RamAndCpuTask ramAndCpuTask);
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
TaskSystem.Task bindDiskTask(SystemUsageBuffer.DiskTask diskTask);
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
TaskSystem.Task bindShutdownHookRegistration(ShutdownHook.Registrar registrar);
|
||||
|
||||
}
|
@ -16,19 +16,16 @@
|
||||
*/
|
||||
package com.djrapitops.plan;
|
||||
|
||||
import com.djrapitops.plan.exceptions.EnableException;
|
||||
import com.djrapitops.plan.settings.ConfigSettingKeyTest;
|
||||
import com.djrapitops.plan.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.settings.config.paths.WebserverSettings;
|
||||
import com.djrapitops.plan.settings.config.paths.key.Setting;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import utilities.RandomData;
|
||||
import utilities.TestSettings;
|
||||
import utilities.mocks.BukkitMockComponent;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collection;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@ -51,7 +48,7 @@ class BukkitSystemTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void bukkitSystemEnables() throws EnableException {
|
||||
void bukkitSystemEnables() {
|
||||
try {
|
||||
system.enable();
|
||||
assertTrue(system.isEnabled());
|
||||
@ -61,13 +58,12 @@ class BukkitSystemTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void bukkitSystemHasDefaultConfigValuesAfterEnable() throws EnableException, IllegalAccessException {
|
||||
void bukkitSystemHasDefaultConfigValuesAfterEnable() throws IllegalAccessException {
|
||||
try {
|
||||
system.enable();
|
||||
PlanConfig config = system.getConfigSystem().getConfig();
|
||||
|
||||
Collection<Setting> serverSettings = ConfigSettingKeyTest.getServerSettings();
|
||||
ConfigSettingKeyTest.assertValidDefaultValuesForAllSettings(config, serverSettings);
|
||||
TestSettings.assertValidDefaultValuesForAllSettings(config, TestSettings.getServerSettings());
|
||||
} finally {
|
||||
system.disable();
|
||||
}
|
||||
|
@ -1,129 +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;
|
||||
|
||||
import com.djrapitops.plan.delivery.webserver.cache.JSONCache;
|
||||
import com.djrapitops.plan.extension.ExtensionServerMethodCallerTask;
|
||||
import com.djrapitops.plan.gathering.timed.BungeePingCounter;
|
||||
import com.djrapitops.plan.gathering.timed.ProxyTPSCounter;
|
||||
import com.djrapitops.plan.gathering.timed.SystemUsageBuffer;
|
||||
import com.djrapitops.plan.gathering.timed.TPSCounter;
|
||||
import com.djrapitops.plan.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.settings.config.paths.DataGatheringSettings;
|
||||
import com.djrapitops.plan.settings.config.paths.TimeSettings;
|
||||
import com.djrapitops.plan.settings.upkeep.NetworkConfigStoreTask;
|
||||
import com.djrapitops.plan.storage.upkeep.DBCleanTask;
|
||||
import com.djrapitops.plan.storage.upkeep.LogsFolderCleanTask;
|
||||
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;
|
||||
|
||||
/**
|
||||
* TaskSystem responsible for registering tasks for Bungee.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Singleton
|
||||
public class BungeeTaskSystem extends TaskSystem {
|
||||
|
||||
private final PlanBungee plugin;
|
||||
private final PlanConfig config;
|
||||
private final TPSCounter tpsCounter;
|
||||
private final BungeePingCounter pingCounter;
|
||||
private final LogsFolderCleanTask logsFolderCleanTask;
|
||||
private final NetworkConfigStoreTask networkConfigStoreTask;
|
||||
private final DBCleanTask dbCleanTask;
|
||||
private final JSONCache.CleanTask jsonCacheCleanTask;
|
||||
private final ExtensionServerMethodCallerTask extensionServerMethodCallerTask;
|
||||
private final SystemUsageBuffer.RamAndCpuTask ramAndCpuTask;
|
||||
private final SystemUsageBuffer.DiskTask diskTask;
|
||||
|
||||
@Inject
|
||||
public BungeeTaskSystem(
|
||||
PlanBungee plugin,
|
||||
PlanConfig config,
|
||||
RunnableFactory runnableFactory,
|
||||
ProxyTPSCounter tpsCounter,
|
||||
BungeePingCounter pingCounter,
|
||||
LogsFolderCleanTask logsFolderCleanTask,
|
||||
NetworkConfigStoreTask networkConfigStoreTask,
|
||||
DBCleanTask dbCleanTask,
|
||||
JSONCache.CleanTask jsonCacheCleanTask,
|
||||
ExtensionServerMethodCallerTask extensionServerMethodCallerTask,
|
||||
SystemUsageBuffer.RamAndCpuTask ramAndCpuTask,
|
||||
SystemUsageBuffer.DiskTask diskTask
|
||||
) {
|
||||
super(runnableFactory);
|
||||
this.plugin = plugin;
|
||||
this.config = config;
|
||||
this.tpsCounter = tpsCounter;
|
||||
|
||||
this.pingCounter = pingCounter;
|
||||
this.logsFolderCleanTask = logsFolderCleanTask;
|
||||
this.networkConfigStoreTask = networkConfigStoreTask;
|
||||
this.dbCleanTask = dbCleanTask;
|
||||
this.jsonCacheCleanTask = jsonCacheCleanTask;
|
||||
this.extensionServerMethodCallerTask = extensionServerMethodCallerTask;
|
||||
this.ramAndCpuTask = ramAndCpuTask;
|
||||
this.diskTask = diskTask;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enable() {
|
||||
registerTasks();
|
||||
}
|
||||
|
||||
private void registerTPSCounter() {
|
||||
long halfSecondTicks = TimeAmount.toTicks(500L, TimeUnit.MILLISECONDS);
|
||||
long secondTicks = TimeAmount.toTicks(1L, TimeUnit.SECONDS);
|
||||
long minuteTicks = TimeAmount.toTicks(1L, TimeUnit.MINUTES);
|
||||
registerTask(tpsCounter).runTaskTimer(minuteTicks, secondTicks);
|
||||
registerTask(ramAndCpuTask).runTaskTimerAsynchronously(minuteTicks - halfSecondTicks, secondTicks);
|
||||
registerTask(diskTask).runTaskTimerAsynchronously(50L * secondTicks, minuteTicks);
|
||||
}
|
||||
|
||||
private void registerTasks() {
|
||||
registerTPSCounter();
|
||||
registerTask(logsFolderCleanTask).runTaskLaterAsynchronously(TimeAmount.toTicks(30L, TimeUnit.SECONDS));
|
||||
|
||||
Long pingDelay = config.get(TimeSettings.PING_SERVER_ENABLE_DELAY);
|
||||
if (pingDelay < TimeUnit.HOURS.toMillis(1L) && config.isTrue(DataGatheringSettings.PING)) {
|
||||
plugin.registerListener(pingCounter);
|
||||
long startDelay = TimeAmount.toTicks(pingDelay, TimeUnit.MILLISECONDS);
|
||||
registerTask(pingCounter).runTaskTimer(startDelay, 40L);
|
||||
}
|
||||
|
||||
// +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(networkConfigStoreTask).runTaskLaterAsynchronously(storeDelay);
|
||||
|
||||
registerTask(dbCleanTask).runTaskTimerAsynchronously(
|
||||
TimeAmount.toTicks(20, TimeUnit.SECONDS),
|
||||
TimeAmount.toTicks(config.get(TimeSettings.CLEAN_DATABASE_PERIOD), TimeUnit.MILLISECONDS)
|
||||
);
|
||||
long minute = TimeAmount.toTicks(1, TimeUnit.MINUTES);
|
||||
registerTask(jsonCacheCleanTask).runTaskTimerAsynchronously(minute, minute);
|
||||
|
||||
long extensionRefreshPeriod = TimeAmount.toTicks(config.get(TimeSettings.EXTENSION_DATA_REFRESH_PERIOD), TimeUnit.MILLISECONDS);
|
||||
registerTask(extensionServerMethodCallerTask).runTaskTimerAsynchronously(
|
||||
TimeAmount.toTicks(30, TimeUnit.SECONDS), extensionRefreshPeriod
|
||||
);
|
||||
}
|
||||
}
|
@ -74,6 +74,7 @@ public class PlanBungee extends BungeePlugin implements PlanPlugin {
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
cancelAllTasks();
|
||||
if (system != null) system.disable();
|
||||
|
||||
logger.info(locale.getString(PluginLang.DISABLED));
|
||||
|
@ -21,10 +21,7 @@ import com.djrapitops.plan.modules.APFModule;
|
||||
import com.djrapitops.plan.modules.PlaceholderModule;
|
||||
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;
|
||||
import com.djrapitops.plan.modules.bungee.BungeeSuperClassBindingModule;
|
||||
import com.djrapitops.plan.modules.bungee.*;
|
||||
import dagger.BindsInstance;
|
||||
import dagger.Component;
|
||||
|
||||
@ -45,7 +42,8 @@ import javax.inject.Singleton;
|
||||
|
||||
ProxySuperClassBindingModule.class,
|
||||
BungeeSuperClassBindingModule.class,
|
||||
BungeeServerPropertiesModule.class
|
||||
BungeeServerPropertiesModule.class,
|
||||
BungeeTaskModule.class
|
||||
})
|
||||
public interface PlanBungeeComponent {
|
||||
|
||||
|
@ -23,9 +23,12 @@
|
||||
*/
|
||||
package com.djrapitops.plan.gathering.timed;
|
||||
|
||||
import com.djrapitops.plan.PlanBungee;
|
||||
import com.djrapitops.plan.TaskSystem;
|
||||
import com.djrapitops.plan.delivery.domain.DateObj;
|
||||
import com.djrapitops.plan.identification.ServerInfo;
|
||||
import com.djrapitops.plan.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.settings.config.paths.DataGatheringSettings;
|
||||
import com.djrapitops.plan.settings.config.paths.TimeSettings;
|
||||
import com.djrapitops.plan.storage.database.DBSystem;
|
||||
import com.djrapitops.plan.storage.database.transactions.events.PingStoreTransaction;
|
||||
@ -50,10 +53,11 @@ import java.util.concurrent.TimeUnit;
|
||||
* @author BrainStone
|
||||
*/
|
||||
@Singleton
|
||||
public class BungeePingCounter extends AbsRunnable implements Listener {
|
||||
public class BungeePingCounter extends TaskSystem.Task implements Listener {
|
||||
|
||||
private final Map<UUID, List<DateObj<Integer>>> playerHistory;
|
||||
|
||||
private final PlanBungee plugin;
|
||||
private final PlanConfig config;
|
||||
private final DBSystem dbSystem;
|
||||
private final ServerInfo serverInfo;
|
||||
@ -61,11 +65,13 @@ public class BungeePingCounter extends AbsRunnable implements Listener {
|
||||
|
||||
@Inject
|
||||
public BungeePingCounter(
|
||||
PlanBungee plugin,
|
||||
PlanConfig config,
|
||||
DBSystem dbSystem,
|
||||
ServerInfo serverInfo,
|
||||
RunnableFactory runnableFactory
|
||||
) {
|
||||
this.plugin = plugin;
|
||||
this.config = config;
|
||||
this.dbSystem = dbSystem;
|
||||
this.serverInfo = serverInfo;
|
||||
@ -102,6 +108,18 @@ public class BungeePingCounter extends AbsRunnable implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(RunnableFactory runnableFactory) {
|
||||
Long startDelay = config.get(TimeSettings.PING_SERVER_ENABLE_DELAY);
|
||||
if (startDelay < TimeUnit.HOURS.toMillis(1L) && config.isTrue(DataGatheringSettings.PING)) {
|
||||
plugin.registerListener(this);
|
||||
|
||||
long delay = TimeAmount.toTicks(startDelay, TimeUnit.MILLISECONDS);
|
||||
long period = 40L;
|
||||
runnableFactory.create(null, this).runTaskTimerAsynchronously(delay, period);
|
||||
}
|
||||
}
|
||||
|
||||
public void addPlayer(ProxiedPlayer player) {
|
||||
playerHistory.put(player.getUniqueId(), new ArrayList<>());
|
||||
}
|
||||
|
@ -67,6 +67,8 @@ public class BungeeServerInfo extends ServerInfo {
|
||||
|
||||
this.server = fromFile.load(null).orElseGet(() -> fromDatabase.load(null)
|
||||
.orElseGet(this::registerServer));
|
||||
this.server.setProxy(true); // Ensure isProxy if loaded from file
|
||||
|
||||
processing.submitNonCritical(this::updateStorage);
|
||||
}
|
||||
|
||||
@ -112,6 +114,6 @@ public class BungeeServerInfo extends ServerInfo {
|
||||
private Server createServerObject() {
|
||||
UUID serverUUID = generateNewUUID();
|
||||
String accessAddress = addresses.getAccessAddress().orElseThrow(() -> new EnableException("Velocity can not have '0.0.0.0' or '' as an address. Set up 'Server.IP' setting."));
|
||||
return new Server(-1, serverUUID, "BungeeCord", accessAddress);
|
||||
return new Server(-1, serverUUID, "BungeeCord", accessAddress, true);
|
||||
}
|
||||
}
|
||||
|
@ -16,8 +16,6 @@
|
||||
*/
|
||||
package com.djrapitops.plan.modules.bungee;
|
||||
|
||||
import com.djrapitops.plan.BungeeTaskSystem;
|
||||
import com.djrapitops.plan.TaskSystem;
|
||||
import com.djrapitops.plan.gathering.BungeeSensor;
|
||||
import com.djrapitops.plan.gathering.ServerSensor;
|
||||
import com.djrapitops.plan.gathering.listeners.BungeeListenerSystem;
|
||||
@ -38,9 +36,6 @@ public interface BungeeSuperClassBindingModule {
|
||||
@Binds
|
||||
ServerInfo bindServerInfo(BungeeServerInfo serverInfo);
|
||||
|
||||
@Binds
|
||||
TaskSystem bindTaskSystem(BungeeTaskSystem taskSystem);
|
||||
|
||||
@Binds
|
||||
ListenerSystem bindListenerSystem(BungeeListenerSystem listenerSystem);
|
||||
|
||||
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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.modules.bungee;
|
||||
|
||||
import com.djrapitops.plan.TaskSystem;
|
||||
import com.djrapitops.plan.delivery.webserver.cache.JSONCache;
|
||||
import com.djrapitops.plan.extension.ExtensionServerDataUpdater;
|
||||
import com.djrapitops.plan.gathering.timed.BungeePingCounter;
|
||||
import com.djrapitops.plan.gathering.timed.ProxyTPSCounter;
|
||||
import com.djrapitops.plan.gathering.timed.SystemUsageBuffer;
|
||||
import com.djrapitops.plan.settings.upkeep.NetworkConfigStoreTask;
|
||||
import com.djrapitops.plan.storage.upkeep.DBCleanTask;
|
||||
import com.djrapitops.plan.storage.upkeep.LogsFolderCleanTask;
|
||||
import dagger.Binds;
|
||||
import dagger.Module;
|
||||
import dagger.multibindings.IntoSet;
|
||||
|
||||
@Module
|
||||
public interface BungeeTaskModule {
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
TaskSystem.Task bindTPSCounter(ProxyTPSCounter counter);
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
TaskSystem.Task bindPingCounter(BungeePingCounter counter);
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
TaskSystem.Task bindNetworkConfigStoreTask(NetworkConfigStoreTask configStoreTask);
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
TaskSystem.Task bindExtensionServerDataUpdater(ExtensionServerDataUpdater extensionServerDataUpdater);
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
TaskSystem.Task bindLogCleanTask(LogsFolderCleanTask logsFolderCleanTask);
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
TaskSystem.Task bindDBCleanTask(DBCleanTask cleanTask);
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
TaskSystem.Task bindJSONCacheCleanTask(JSONCache.CleanTask cleanTask);
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
TaskSystem.Task bindRamAndCpuTask(SystemUsageBuffer.RamAndCpuTask ramAndCpuTask);
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
TaskSystem.Task bindDiskTask(SystemUsageBuffer.DiskTask diskTask);
|
||||
|
||||
}
|
@ -10,6 +10,7 @@ dependencies {
|
||||
compile "com.github.ben-manes.caffeine:caffeine:$caffeineVersion"
|
||||
compile "com.h2database:h2:$h2Version"
|
||||
compile "mysql:mysql-connector-java:$mysqlVersion"
|
||||
compile "org.xerial:sqlite-jdbc:$sqliteVersion"
|
||||
compile "com.zaxxer:HikariCP:$hikariVersion"
|
||||
compile "org.slf4j:slf4j-nop:$slf4jVersion"
|
||||
compile "org.slf4j:slf4j-api:$slf4jVersion"
|
||||
|
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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.storage.database.queries.Query;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Service for sourcing, mapping and consuming data.
|
||||
* <p>
|
||||
* The service is in charge of two data flows:
|
||||
* - push, given to consumers
|
||||
* - pull, obtained from sources
|
||||
* <p>
|
||||
* The mappers facilitate a one way type transformation if needed.
|
||||
* <p>
|
||||
* The interface is very abstract about how data is obtained,
|
||||
* but here are my general ideas of where the abstraction is coming from.
|
||||
* - push cause one or multiple consumers to modify stored data
|
||||
* - pull cause one or multiple suppliers to fetch stored data
|
||||
* - mappers are stateless type transformers in memory
|
||||
* <p>
|
||||
* Example use-case:
|
||||
* - PlayerJoinEvent is mapped to a generic event
|
||||
* - that generic event is then consumed and mapped until the data is in a database.
|
||||
* <p>
|
||||
* - Some kind of data is wanted to place on a web page
|
||||
* - It is requested and the suppliers and mappers give the wanted type of data.
|
||||
* <p>
|
||||
* Further research needed:
|
||||
* - Can this limited type system represent types of data that need parameters
|
||||
* (such as differentiate between two servers data)
|
||||
*/
|
||||
public interface DataService {
|
||||
|
||||
<M> DataService push(Class<M> type, M data);
|
||||
|
||||
<S> Optional<S> pull(Class<S> type);
|
||||
|
||||
<S, P> Optional<S> pull(Class<S> type, P parameter);
|
||||
|
||||
<A, B> B mapTo(Class<B> toType, A from);
|
||||
|
||||
default <S, P> Optional<S> pull(Class<S> type, Class<P> parameterType) {
|
||||
return pull(type, () -> pull(parameterType).orElse(null));
|
||||
}
|
||||
|
||||
default <S, P> Optional<S> pull(Class<S> type, Supplier<P> parameter) {
|
||||
return pull(type, parameter.get());
|
||||
}
|
||||
|
||||
<A, B> DataService registerMapper(Class<A> typeA, Class<B> typeB, Function<A, B> mapper);
|
||||
|
||||
<M> DataService registerConsumer(Class<M> type, Consumer<M> consumer);
|
||||
|
||||
<S> DataService registerSupplier(Class<S> type, Supplier<S> supplier);
|
||||
|
||||
<P, S> DataService registerSupplier(Class<S> type, Class<P> parameterType, Function<P, S> supplierWithParameter);
|
||||
|
||||
<P, S> DataService registerDBSupplier(Class<S> type, Class<P> parameterType, Function<P, Query<S>> supplierWithParameter);
|
||||
|
||||
}
|
194
Plan/common/src/main/java/com/djrapitops/plan/DataSvc.java
Normal file
194
Plan/common/src/main/java/com/djrapitops/plan/DataSvc.java
Normal file
@ -0,0 +1,194 @@
|
||||
/*
|
||||
* 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.storage.database.DBSystem;
|
||||
import com.djrapitops.plan.storage.database.queries.Query;
|
||||
import dagger.Lazy;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@Singleton
|
||||
public class DataSvc implements DataService {
|
||||
|
||||
private final MultiHashMap<Class, Mapper> mappers;
|
||||
private final MultiHashMap<Class, Mapper> mappersReverse;
|
||||
private final Map<Class, Supplier> suppliers;
|
||||
private final Map<ClassPair, Function> suppliersWithParameter;
|
||||
private final MultiHashMap<Class, Consumer> consumers;
|
||||
|
||||
private final Lazy<DBSystem> dbSystem;
|
||||
|
||||
@Inject
|
||||
public DataSvc(
|
||||
Lazy<DBSystem> dbSystem
|
||||
) {
|
||||
this.dbSystem = dbSystem;
|
||||
mappers = new MultiHashMap<>();
|
||||
mappersReverse = new MultiHashMap<>();
|
||||
suppliers = new ConcurrentHashMap<>();
|
||||
suppliersWithParameter = new ConcurrentHashMap<>();
|
||||
consumers = new MultiHashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <A> DataService push(Class<A> type, A data) {
|
||||
if (data == null) return this;
|
||||
List<Mapper> mappers = this.mappers.get(type);
|
||||
for (Mapper mapper : mappers) {
|
||||
push(mapper.typeB, mapper.func.apply(data));
|
||||
}
|
||||
List<Consumer> consumers = this.consumers.get(type);
|
||||
for (Consumer<A> consumer : consumers) {
|
||||
consumer.accept(data);
|
||||
}
|
||||
if (mappers.isEmpty() && consumers.isEmpty()) {
|
||||
System.out.println("WARN: Nothing consumed " + type);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <A> Optional<A> pull(Class<A> type) {
|
||||
Supplier present = this.suppliers.get(type);
|
||||
if (present != null) return Optional.ofNullable((A) present.get());
|
||||
|
||||
List<Mapper> mappers = this.mappersReverse.get(type);
|
||||
for (Mapper mapper : mappers) {
|
||||
Optional found = pull(mapper.typeA)
|
||||
.map(data -> mapper.func.apply(data));
|
||||
if (found.isPresent()) return found;
|
||||
}
|
||||
|
||||
System.out.println("WARN: Nothing supplied " + type);
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <A, B> B mapTo(Class<B> toType, A from) {
|
||||
List<Mapper> mappers = this.mappers.get(from.getClass());
|
||||
for (Mapper mapper : mappers) {
|
||||
if (mapper.typeB.equals(toType)) {
|
||||
return toType.cast(mapper.func.apply(from));
|
||||
}
|
||||
}
|
||||
// TODO Figure out type mapping resolution when it needs more than one mapping
|
||||
System.out.println("WARN: No mapper for " + from.getClass() + " -> " + toType);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <A, B> DataService registerMapper(Class<A> typeA, Class<B> typeB, Function<A, B> mapper) {
|
||||
Mapper<A, B> asWrapper = new Mapper<>(typeA, typeB, mapper);
|
||||
// TODO Prevent two mappers for same 2 types with a data structure
|
||||
mappers.putOne(typeA, asWrapper);
|
||||
mappersReverse.putOne(typeB, asWrapper);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <A> DataService registerConsumer(Class<A> type, Consumer<A> consumer) {
|
||||
consumers.putOne(type, consumer);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <A> DataService registerSupplier(Class<A> type, Supplier<A> supplier) {
|
||||
suppliers.put(type, supplier);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S, P> Optional<S> pull(Class<S> type, P parameter) {
|
||||
if (parameter == null) return Optional.empty();
|
||||
Function<P, S> function = suppliersWithParameter.get(new ClassPair<>(type, parameter.getClass()));
|
||||
return function != null ? Optional.of(function.apply(parameter)) : Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <P, S> DataService registerSupplier(Class<S> type, Class<P> parameterType, Function<P, S> supplierWithParameter) {
|
||||
suppliersWithParameter.put(new ClassPair<>(type, parameterType), supplierWithParameter);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <P, S> DataService registerDBSupplier(Class<S> type, Class<P> parameterType, Function<P, Query<S>> queryVisitor) {
|
||||
return registerSupplier(type, parameterType, parameter -> dbSystem.get().getDatabase().query(queryVisitor.apply(parameter)));
|
||||
}
|
||||
|
||||
private static class ClassPair<A, B> {
|
||||
final Class<A> a;
|
||||
final Class<B> b;
|
||||
|
||||
public ClassPair(Class<A> a, Class<B> b) {
|
||||
this.a = a;
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
ClassPair<?, ?> classPair = (ClassPair<?, ?>) o;
|
||||
return a.equals(classPair.a) &&
|
||||
b.equals(classPair.b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
private static class KeyValuePair<K, V> {
|
||||
final K key;
|
||||
final V value;
|
||||
|
||||
public KeyValuePair(K key, V value) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
private static class MultiHashMap<A, B> extends ConcurrentHashMap<A, List<B>> {
|
||||
|
||||
void putOne(A key, B value) {
|
||||
List<B> values = getOrDefault(key, new ArrayList<>());
|
||||
values.add(value);
|
||||
put(key, values);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class Mapper<A, B> {
|
||||
Class<A> typeA;
|
||||
Class<B> typeB;
|
||||
Function<A, B> func;
|
||||
|
||||
public Mapper(Class<A> typeA, Class<B> typeB, Function<A, B> func) {
|
||||
this.typeA = typeA;
|
||||
this.typeB = typeB;
|
||||
this.func = func;
|
||||
}
|
||||
}
|
||||
}
|
@ -47,4 +47,8 @@ public interface PlanPlugin extends IPlugin {
|
||||
}
|
||||
|
||||
void registerCommand(Subcommand command);
|
||||
|
||||
default void cancelAllTasks() {
|
||||
getRunnableFactory().cancelAllKnownTasks();
|
||||
}
|
||||
}
|
||||
|
@ -17,31 +17,36 @@
|
||||
package com.djrapitops.plan;
|
||||
|
||||
import com.djrapitops.plugin.task.AbsRunnable;
|
||||
import com.djrapitops.plugin.task.PluginRunnable;
|
||||
import com.djrapitops.plugin.task.RunnableFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* TaskSystem that registers tasks that were previously registered inside Plugin classes.
|
||||
*
|
||||
* Subclasses register actual tasks.
|
||||
* TaskSystem that registers tasks for the plugin.
|
||||
* See platform specific [Platform]TaskModule classes for what Tasks are registered.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public abstract class TaskSystem implements SubSystem {
|
||||
@Singleton
|
||||
public class TaskSystem implements SubSystem {
|
||||
|
||||
protected final RunnableFactory runnableFactory;
|
||||
private final RunnableFactory runnableFactory;
|
||||
private final Set<Task> tasks;
|
||||
|
||||
protected TaskSystem(RunnableFactory runnableFactory) {
|
||||
@Inject
|
||||
public TaskSystem(
|
||||
RunnableFactory runnableFactory,
|
||||
Set<Task> tasks
|
||||
) {
|
||||
this.runnableFactory = runnableFactory;
|
||||
this.tasks = tasks;
|
||||
}
|
||||
|
||||
protected PluginRunnable registerTask(AbsRunnable runnable) {
|
||||
String taskName = runnable.getClass().getSimpleName();
|
||||
return registerTask(taskName, runnable);
|
||||
}
|
||||
|
||||
public PluginRunnable registerTask(String name, AbsRunnable runnable) {
|
||||
return runnableFactory.create(name, runnable);
|
||||
@Override
|
||||
public void enable() {
|
||||
for (Task task : tasks) task.register(runnableFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -49,4 +54,8 @@ public abstract class TaskSystem implements SubSystem {
|
||||
runnableFactory.cancelAllKnownTasks();
|
||||
}
|
||||
|
||||
public static abstract class Task extends AbsRunnable {
|
||||
public abstract void register(RunnableFactory runnableFactory);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -22,6 +22,6 @@ public class ConsoleChatFormatter extends ChatFormatter {
|
||||
|
||||
@Override
|
||||
public int getWidth(String part) {
|
||||
return part.length() - (StringUtils.countMatches(part, '§') * 2);
|
||||
return part.length() - (StringUtils.countMatches(part, '\u00a7') * 2);
|
||||
}
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ public class PlayerKillMutator {
|
||||
Map<String, Object> killMap = new HashMap<>();
|
||||
killMap.put("date", formatters.secondLong().apply(kill.getDate()));
|
||||
killMap.put("victim", kill.getVictimName().orElse(kill.getVictim().toString()));
|
||||
killMap.put("killer", kill.getKillerName().orElse("Missing UUID")); // TODO Kills should support killer UUID
|
||||
killMap.put("killer", kill.getKillerName().orElse(kill.getKiller().toString()));
|
||||
killMap.put("weapon", kill.getWeapon());
|
||||
return killMap;
|
||||
}
|
||||
|
@ -288,8 +288,8 @@ public class SessionsMutator {
|
||||
kill -> {
|
||||
Map<String, Object> killMap = new HashMap<>();
|
||||
killMap.put("date", formatters.secondLong().apply(kill.getDate()));
|
||||
killMap.put("victim", kill.getVictimName());
|
||||
killMap.put("killer", sessionMap.get("player_name"));
|
||||
killMap.put("victim", kill.getVictimName().orElse(kill.getVictim().toString()));
|
||||
killMap.put("killer", playerName);
|
||||
killMap.put("weapon", kill.getWeapon());
|
||||
return killMap;
|
||||
}
|
||||
|
@ -16,7 +16,6 @@
|
||||
*/
|
||||
package com.djrapitops.plan.delivery.export;
|
||||
|
||||
import com.djrapitops.plan.TaskSystem;
|
||||
import com.djrapitops.plan.identification.Server;
|
||||
import com.djrapitops.plan.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.settings.config.paths.ExportSettings;
|
||||
@ -24,6 +23,7 @@ import com.djrapitops.plan.storage.database.DBSystem;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.ServerQueries;
|
||||
import com.djrapitops.plan.utilities.logging.ErrorLogger;
|
||||
import com.djrapitops.plugin.api.TimeAmount;
|
||||
import com.djrapitops.plugin.task.RunnableFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
@ -41,8 +41,8 @@ public class ExportScheduler {
|
||||
|
||||
private final PlanConfig config;
|
||||
private final DBSystem dbSystem;
|
||||
private final TaskSystem taskSystem;
|
||||
|
||||
private final RunnableFactory runnableFactory;
|
||||
private final Exporter exporter;
|
||||
private final ErrorLogger errorLogger;
|
||||
|
||||
@ -50,13 +50,13 @@ public class ExportScheduler {
|
||||
public ExportScheduler(
|
||||
PlanConfig config,
|
||||
DBSystem dbSystem,
|
||||
TaskSystem taskSystem,
|
||||
RunnableFactory runnableFactory,
|
||||
Exporter exporter,
|
||||
ErrorLogger errorLogger
|
||||
) {
|
||||
this.config = config;
|
||||
this.dbSystem = dbSystem;
|
||||
this.taskSystem = taskSystem;
|
||||
this.runnableFactory = runnableFactory;
|
||||
this.exporter = exporter;
|
||||
this.errorLogger = errorLogger;
|
||||
}
|
||||
@ -68,7 +68,7 @@ public class ExportScheduler {
|
||||
|
||||
private void schedulePlayersPageExport() {
|
||||
long period = TimeAmount.toTicks(config.get(ExportSettings.EXPORT_PERIOD), TimeUnit.MILLISECONDS);
|
||||
taskSystem.registerTask("Players page export",
|
||||
runnableFactory.create("Players page export",
|
||||
new ExportTask(exporter, Exporter::exportPlayersPage, errorLogger)
|
||||
).runTaskTimerAsynchronously(0L, period);
|
||||
}
|
||||
@ -84,14 +84,14 @@ public class ExportScheduler {
|
||||
long offset = period / serverCount;
|
||||
|
||||
Optional<Server> proxy = servers.stream().filter(Server::isProxy).findFirst();
|
||||
proxy.ifPresent(mainServer -> taskSystem.registerTask("Network export",
|
||||
proxy.ifPresent(mainServer -> runnableFactory.create("Network export",
|
||||
new ExportTask(exporter, same -> same.exportServerPage(mainServer), errorLogger))
|
||||
.runTaskTimerAsynchronously(0L, period)
|
||||
);
|
||||
|
||||
int offsetMultiplier = proxy.isPresent() ? 1 : 0; // Delay first server export if on a network.
|
||||
for (Server server : servers) {
|
||||
taskSystem.registerTask("Server export",
|
||||
runnableFactory.create("Server export",
|
||||
new ExportTask(exporter, same -> {
|
||||
same.exportServerPage(server);
|
||||
same.exportServerJSON(server);
|
||||
|
@ -215,7 +215,7 @@ public class NetworkPageExporter extends FileExporter {
|
||||
() -> files.getResourceFromJar("web/" + resourceName).asWebResource());
|
||||
Path to = toDirectory.resolve(resourceName);
|
||||
|
||||
if (resourceName.endsWith(".css")) {
|
||||
if (resourceName.endsWith(".css") || resourceName.endsWith("color-selector.js")) {
|
||||
export(to, theme.replaceThemeColors(resource.asString()));
|
||||
} else if ("js/network-values.js".equalsIgnoreCase(resourceName) || "js/sessionAccordion.js".equalsIgnoreCase(resourceName)) {
|
||||
String relativePlayerLink = toRelativePathFromRoot("player");
|
||||
|
@ -191,7 +191,7 @@ public class PlayerPageExporter extends FileExporter {
|
||||
() -> files.getResourceFromJar("web/" + resourceName).asWebResource());
|
||||
Path to = toDirectory.resolve(resourceName);
|
||||
|
||||
if (resourceName.endsWith(".css")) {
|
||||
if (resourceName.endsWith(".css") || resourceName.endsWith("color-selector.js")) {
|
||||
export(to, theme.replaceThemeColors(resource.asString()));
|
||||
} else if (Resource.isTextResource(resourceName)) {
|
||||
export(to, resource.asString());
|
||||
|
@ -164,7 +164,7 @@ public class PlayersPageExporter extends FileExporter {
|
||||
() -> files.getResourceFromJar("web/" + resourceName).asWebResource());
|
||||
Path to = toDirectory.resolve(resourceName);
|
||||
|
||||
if (resourceName.endsWith(".css")) {
|
||||
if (resourceName.endsWith(".css") || resourceName.endsWith("color-selector.js")) {
|
||||
export(to, theme.replaceThemeColors(resource.asString()));
|
||||
} else if (Resource.isTextResource(resourceName)) {
|
||||
export(to, resource.asString());
|
||||
|
@ -234,7 +234,7 @@ public class ServerPageExporter extends FileExporter {
|
||||
() -> files.getResourceFromJar("web/" + resourceName).asWebResource());
|
||||
Path to = toDirectory.resolve(resourceName);
|
||||
|
||||
if (resourceName.endsWith(".css")) {
|
||||
if (resourceName.endsWith(".css") || resourceName.endsWith("color-selector.js")) {
|
||||
export(to, theme.replaceThemeColors(resource.asString()));
|
||||
} else if (Resource.isTextResource(resourceName)) {
|
||||
export(to, resource.asString());
|
||||
|
@ -16,6 +16,8 @@
|
||||
*/
|
||||
package com.djrapitops.plan.delivery.rendering.html.icon;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public enum Color {
|
||||
@ -61,4 +63,8 @@ public enum Color {
|
||||
public String getHtmlClass() {
|
||||
return htmlClass;
|
||||
}
|
||||
|
||||
public String getBackgroundColorClass() {
|
||||
return StringUtils.replace(htmlClass, "col-", "bg-");
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.delivery.rendering.html.structure;
|
||||
|
||||
import com.djrapitops.plan.extension.table.Table;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class DynamicHtmlTable implements HtmlTable {
|
||||
private final Header[] headers;
|
||||
private final List<Object[]> rows;
|
||||
|
||||
public DynamicHtmlTable(Header[] headers, List<Object[]> rows) {
|
||||
this.headers = headers;
|
||||
this.rows = rows;
|
||||
}
|
||||
|
||||
public DynamicHtmlTable(Table table) {
|
||||
this(HtmlTable.mapToHeaders(table), table.getRows());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toHtml() {
|
||||
return "<div class=\"table-responsive\">" +
|
||||
"<table class=\"table table-bordered table-striped table-hover player-plugin-table dataTable\">" +
|
||||
buildTableHeader() +
|
||||
buildTableBody() +
|
||||
"</table>" +
|
||||
"</div>";
|
||||
}
|
||||
|
||||
private String buildTableHeader() {
|
||||
StringBuilder builtHeader = new StringBuilder("<thead><tr>");
|
||||
for (Header header : headers) {
|
||||
builtHeader.append("<th>")
|
||||
.append(header.getIcon().toHtml())
|
||||
.append(' ')
|
||||
.append(header.getText())
|
||||
.append("</th>");
|
||||
}
|
||||
builtHeader.append("</tr></thead>");
|
||||
return builtHeader.toString();
|
||||
}
|
||||
|
||||
private String buildTableBody() {
|
||||
StringBuilder builtBody = new StringBuilder();
|
||||
builtBody.append("<tbody>");
|
||||
if (rows.isEmpty()) {
|
||||
appendRow(builtBody, "No Data");
|
||||
}
|
||||
for (Object[] row : rows) {
|
||||
appendRow(builtBody, row);
|
||||
}
|
||||
return builtBody.append("</tbody>").toString();
|
||||
}
|
||||
|
||||
private void appendRow(StringBuilder builtBody, Object... row) {
|
||||
int headerLength = row.length - 1;
|
||||
builtBody.append("<tr>");
|
||||
for (int i = 0; i < headers.length; i++) {
|
||||
try {
|
||||
if (i > headerLength) {
|
||||
builtBody.append("<td>-");
|
||||
} else {
|
||||
builtBody.append("<td>");
|
||||
Object value = row[i];
|
||||
builtBody.append(value != null ? value : '-');
|
||||
}
|
||||
builtBody.append("</td>");
|
||||
} catch (ClassCastException | ArrayIndexOutOfBoundsException e) {
|
||||
throw new IllegalStateException("Invalid formatter given at index " + i + ": " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
builtBody.append("</tr>");
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.delivery.rendering.html.structure;
|
||||
|
||||
import com.djrapitops.plan.delivery.rendering.html.icon.Color;
|
||||
import com.djrapitops.plan.delivery.rendering.html.icon.Icon;
|
||||
import com.djrapitops.plan.extension.table.Table;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public interface HtmlTable {
|
||||
|
||||
static HtmlTable fromExtensionTable(Table table, com.djrapitops.plan.extension.icon.Color tableColor) {
|
||||
return fromExtensionTable(table, Color.getByName(tableColor.name()).orElse(Color.NONE));
|
||||
}
|
||||
|
||||
static HtmlTable fromExtensionTable(Table table, Color tableColor) {
|
||||
if (table.getRows().size() > 50) {
|
||||
return new DynamicHtmlTable(table);
|
||||
} else {
|
||||
return new HtmlTableWithColoredHeader(table, tableColor);
|
||||
}
|
||||
}
|
||||
|
||||
static Header[] mapToHeaders(Table table) {
|
||||
ArrayList<Header> headers = new ArrayList<>();
|
||||
|
||||
com.djrapitops.plan.extension.icon.Icon[] icons = table.getIcons();
|
||||
String[] columns = table.getColumns();
|
||||
for (int i = 0; i < columns.length; i++) {
|
||||
String column = columns[i];
|
||||
if (column == null) {
|
||||
break;
|
||||
}
|
||||
headers.add(new Header(Icon.fromExtensionIcon(icons[i]), column));
|
||||
}
|
||||
|
||||
return headers.toArray(new Header[0]);
|
||||
}
|
||||
|
||||
String toHtml();
|
||||
|
||||
class Header {
|
||||
private final Icon icon;
|
||||
private final String text;
|
||||
|
||||
public Header(Icon icon, String text) {
|
||||
this.icon = icon;
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public Icon getIcon() {
|
||||
return icon;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.delivery.rendering.html.structure;
|
||||
|
||||
import com.djrapitops.plan.delivery.rendering.html.icon.Color;
|
||||
import com.djrapitops.plan.extension.table.Table;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class HtmlTableWithColoredHeader implements HtmlTable {
|
||||
private final Header[] headers;
|
||||
private final Color headerColor;
|
||||
private final List<Object[]> rows;
|
||||
|
||||
public HtmlTableWithColoredHeader(Header[] headers, Color headerColor, List<Object[]> rows) {
|
||||
this.headers = headers;
|
||||
this.headerColor = headerColor;
|
||||
this.rows = rows;
|
||||
}
|
||||
|
||||
public HtmlTableWithColoredHeader(Table table, Color headerColor) {
|
||||
this(HtmlTable.mapToHeaders(table), headerColor, table.getRows());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toHtml() {
|
||||
return "<div class=\"scrollbar\">" +
|
||||
"<table class=\"table table-striped\">" +
|
||||
buildTableHeader() +
|
||||
buildTableBody() +
|
||||
"</table>" +
|
||||
"</div>";
|
||||
}
|
||||
|
||||
private String buildTableHeader() {
|
||||
StringBuilder builtHeader = new StringBuilder("<thead class=\"" + headerColor.getBackgroundColorClass() + "\"><tr>");
|
||||
for (Header header : headers) {
|
||||
builtHeader.append("<th>")
|
||||
.append(header.getIcon().toHtml())
|
||||
.append(' ')
|
||||
.append(header.getText())
|
||||
.append("</th>");
|
||||
}
|
||||
builtHeader.append("</tr></thead>");
|
||||
return builtHeader.toString();
|
||||
}
|
||||
|
||||
private String buildTableBody() {
|
||||
StringBuilder builtBody = new StringBuilder();
|
||||
builtBody.append("<tbody>");
|
||||
if (rows.isEmpty()) {
|
||||
appendRow(builtBody, "No Data");
|
||||
}
|
||||
for (Object[] row : rows) {
|
||||
appendRow(builtBody, row);
|
||||
}
|
||||
return builtBody.append("</tbody>").toString();
|
||||
}
|
||||
|
||||
private void appendRow(StringBuilder builtBody, Object... row) {
|
||||
int headerLength = row.length - 1;
|
||||
builtBody.append("<tr>");
|
||||
for (int i = 0; i < headers.length; i++) {
|
||||
try {
|
||||
if (i > headerLength) {
|
||||
builtBody.append("<td>-");
|
||||
} else {
|
||||
builtBody.append("<td>");
|
||||
Object value = row[i];
|
||||
builtBody.append(value != null ? value : '-');
|
||||
}
|
||||
builtBody.append("</td>");
|
||||
} catch (ClassCastException | ArrayIndexOutOfBoundsException e) {
|
||||
throw new IllegalStateException("Invalid formatter given at index " + i + ": " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
builtBody.append("</tr>");
|
||||
}
|
||||
|
||||
}
|
@ -185,7 +185,7 @@ public class PlayerPluginTab implements Comparable<PlayerPluginTab> {
|
||||
if (tableData.isWideTable()) {
|
||||
hasWideTable = true;
|
||||
}
|
||||
builder.append(tableData.getHtmlTable().buildHtml());
|
||||
builder.append(tableData.getHtmlTable().toHtml());
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
@ -207,7 +207,7 @@ public class ServerPluginTabs {
|
||||
private String buildTablesHtml(ExtensionTabData tabData) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (ExtensionTableData tableData : tabData.getTableData()) {
|
||||
builder.append(tableData.getHtmlTable().buildHtml());
|
||||
builder.append(tableData.getHtmlTable().toHtml());
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
@ -16,11 +16,13 @@
|
||||
*/
|
||||
package com.djrapitops.plan.delivery.webserver.cache;
|
||||
|
||||
import com.djrapitops.plan.TaskSystem;
|
||||
import com.djrapitops.plan.delivery.web.resolver.MimeType;
|
||||
import com.djrapitops.plan.delivery.web.resolver.Response;
|
||||
import com.djrapitops.plan.delivery.webserver.resolver.json.RootJSONResolver;
|
||||
import com.djrapitops.plan.storage.file.ResourceCache;
|
||||
import com.djrapitops.plugin.task.AbsRunnable;
|
||||
import com.djrapitops.plugin.api.TimeAmount;
|
||||
import com.djrapitops.plugin.task.RunnableFactory;
|
||||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@ -141,7 +143,7 @@ public class JSONCache {
|
||||
}
|
||||
|
||||
@Singleton
|
||||
public static class CleanTask extends AbsRunnable {
|
||||
public static class CleanTask extends TaskSystem.Task {
|
||||
|
||||
@Inject
|
||||
public CleanTask() {
|
||||
@ -153,5 +155,11 @@ public class JSONCache {
|
||||
cleanUp();
|
||||
ResourceCache.cleanUp();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(RunnableFactory runnableFactory) {
|
||||
long minute = TimeAmount.toTicks(1, TimeUnit.MINUTES);
|
||||
runnableFactory.create(null, this).runTaskTimerAsynchronously(minute, minute);
|
||||
}
|
||||
}
|
||||
}
|
@ -16,10 +16,15 @@
|
||||
*/
|
||||
package com.djrapitops.plan.extension;
|
||||
|
||||
import com.djrapitops.plugin.task.AbsRunnable;
|
||||
import com.djrapitops.plan.TaskSystem;
|
||||
import com.djrapitops.plan.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.settings.config.paths.TimeSettings;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Task for updating {@link DataExtension} server values periodically.
|
||||
@ -27,17 +32,29 @@ import javax.inject.Singleton;
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Singleton
|
||||
public class ExtensionServerMethodCallerTask extends AbsRunnable {
|
||||
public class ExtensionServerDataUpdater extends TaskSystem.Task {
|
||||
|
||||
private final ExtensionSvc service;
|
||||
private final PlanConfig config;
|
||||
|
||||
@Inject
|
||||
public ExtensionServerMethodCallerTask(ExtensionSvc service) {
|
||||
public ExtensionServerDataUpdater(
|
||||
ExtensionSvc service,
|
||||
PlanConfig config
|
||||
) {
|
||||
this.service = service;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
service.updateServerValues(CallEvents.SERVER_PERIODICAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(RunnableFactory runnableFactory) {
|
||||
long period = TimeAmount.toTicks(config.get(TimeSettings.EXTENSION_DATA_REFRESH_PERIOD), TimeUnit.MILLISECONDS);
|
||||
long delay = TimeAmount.toTicks(30, TimeUnit.SECONDS);
|
||||
runnableFactory.create(null, this).runTaskTimerAsynchronously(delay, period);
|
||||
}
|
||||
}
|
@ -16,15 +16,10 @@
|
||||
*/
|
||||
package com.djrapitops.plan.extension.implementation.results;
|
||||
|
||||
import com.djrapitops.plan.data.element.TableContainer;
|
||||
import com.djrapitops.plan.delivery.rendering.html.structure.HtmlTable;
|
||||
import com.djrapitops.plan.extension.icon.Color;
|
||||
import com.djrapitops.plan.extension.icon.Icon;
|
||||
import com.djrapitops.plan.extension.table.Table;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
@ -44,41 +39,8 @@ public class ExtensionTableData implements Comparable<ExtensionTableData> {
|
||||
this.tableColor = tableColor;
|
||||
}
|
||||
|
||||
public TableContainer getHtmlTable() {
|
||||
String[] columns = table.getColumns();
|
||||
Icon[] icons = table.getIcons();
|
||||
List<Object[]> rows = table.getRows();
|
||||
|
||||
String[] header = buildHeader(columns, icons);
|
||||
|
||||
TableContainer htmlTable = new TableContainer(header);
|
||||
if (rows.size() > 50) {
|
||||
htmlTable.useJqueryDataTables(); // Use a jQuery data table since there are a lot of rows.
|
||||
} else {
|
||||
String colorName = com.djrapitops.plan.delivery.rendering.html.icon.Color.getByName(tableColor.name()).orElse(com.djrapitops.plan.delivery.rendering.html.icon.Color.NONE).getHtmlClass()
|
||||
.replace("col-", ""); // TODO after PluginData deprecation, change this thing
|
||||
htmlTable.setColor(colorName);
|
||||
}
|
||||
|
||||
for (Object[] row : rows) {
|
||||
htmlTable.addRow(Arrays.stream(row).map(value -> value != null ? value.toString() : null).toArray(Serializable[]::new));
|
||||
}
|
||||
|
||||
return htmlTable;
|
||||
}
|
||||
|
||||
private String[] buildHeader(String[] columns, Icon[] icons) {
|
||||
ArrayList<String> header = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < columns.length; i++) {
|
||||
String column = columns[i];
|
||||
if (column == null) {
|
||||
break;
|
||||
}
|
||||
header.add(com.djrapitops.plan.delivery.rendering.html.icon.Icon.fromExtensionIcon(icons[i]).toHtml() + ' ' + column);
|
||||
}
|
||||
|
||||
return header.toArray(new String[0]);
|
||||
public HtmlTable getHtmlTable() {
|
||||
return HtmlTable.fromExtensionTable(table, tableColor);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -16,6 +16,9 @@
|
||||
*/
|
||||
package com.djrapitops.plan.gathering;
|
||||
|
||||
import com.djrapitops.plan.TaskSystem;
|
||||
import com.djrapitops.plugin.task.RunnableFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
@ -78,4 +81,22 @@ public class ShutdownHook extends Thread {
|
||||
Logger.getGlobal().log(Level.SEVERE, "Plan failed to save sessions on JVM shutdown.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Singleton
|
||||
public static class Registrar extends TaskSystem.Task {
|
||||
private final ShutdownHook shutdownHook;
|
||||
|
||||
@Inject
|
||||
public Registrar(ShutdownHook shutdownHook) {this.shutdownHook = shutdownHook;}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
shutdownHook.register();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(RunnableFactory runnableFactory) {
|
||||
runnableFactory.create(null, this).runTaskAsynchronously();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,13 +23,13 @@ import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* This class is used to store data about a player kill inside the UserInfo
|
||||
* object.
|
||||
* Represents a player vs player kill.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class PlayerKill implements DateHolder {
|
||||
|
||||
private final UUID killer;
|
||||
private final UUID victim;
|
||||
private final String weapon;
|
||||
private final long date;
|
||||
@ -40,31 +40,32 @@ public class PlayerKill implements DateHolder {
|
||||
/**
|
||||
* Creates a PlayerKill object with given parameters.
|
||||
*
|
||||
* @param killer UUID of the killer.
|
||||
* @param victim UUID of the victim.
|
||||
* @param weapon Weapon used.
|
||||
* @param date Epoch millisecond at which the kill occurred.
|
||||
*/
|
||||
public PlayerKill(UUID victim, String weapon, long date) {
|
||||
public PlayerKill(UUID killer, UUID victim, String weapon, long date) {
|
||||
this.killer = killer;
|
||||
this.victim = victim;
|
||||
this.weapon = weapon;
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
public PlayerKill(UUID victim, String weapon, long date, String victimName) {
|
||||
this(victim, weapon, date);
|
||||
public PlayerKill(UUID killer, UUID victim, String weapon, long date, String victimName) {
|
||||
this(killer, victim, weapon, date);
|
||||
this.victimName = victimName;
|
||||
}
|
||||
|
||||
public PlayerKill(UUID victim, String weapon, long date, String victimName, String killerName) {
|
||||
this(victim, weapon, date, victimName);
|
||||
public PlayerKill(UUID killer, UUID victim, String weapon, long date, String victimName, String killerName) {
|
||||
this(killer, victim, weapon, date, victimName);
|
||||
this.killerName = killerName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the victim's UUID.
|
||||
*
|
||||
* @return UUID of the victim.
|
||||
*/
|
||||
public UUID getKiller() {
|
||||
return killer;
|
||||
}
|
||||
|
||||
public UUID getVictim() {
|
||||
return victim;
|
||||
}
|
||||
@ -97,25 +98,27 @@ public class PlayerKill implements DateHolder {
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
PlayerKill that = (PlayerKill) o;
|
||||
return date == that.date &&
|
||||
Objects.equals(killer, that.killer) &&
|
||||
Objects.equals(victim, that.victim) &&
|
||||
Objects.equals(weapon, that.weapon);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(victim, date, weapon);
|
||||
return Objects.hash(killer, victim, date, weapon);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PlayerKill{" +
|
||||
"killer=" + killer + ", " +
|
||||
"victim=" + victim + ", " +
|
||||
"date=" + date + ", " +
|
||||
"weapon='" + weapon + "'}";
|
||||
}
|
||||
|
||||
public boolean isSelfKill() {
|
||||
return getVictimName().map(v -> v.equals(killerName)).orElse(false);
|
||||
return killer.equals(victim);
|
||||
}
|
||||
|
||||
public boolean isNotSelfKill() {
|
||||
|
@ -1,39 +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.gathering.importing;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
/**
|
||||
* Placeholder for a ImportSystem.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Singleton
|
||||
public class EmptyImportSystem extends ImportSystem {
|
||||
|
||||
@Inject
|
||||
public EmptyImportSystem() {
|
||||
// Inject constructor required for dagger
|
||||
}
|
||||
|
||||
@Override
|
||||
void registerImporters() {
|
||||
// No importers to register.
|
||||
}
|
||||
}
|
@ -20,30 +20,34 @@ import com.djrapitops.plan.SubSystem;
|
||||
import com.djrapitops.plan.gathering.importing.importers.Importer;
|
||||
import com.djrapitops.plugin.utilities.Verify;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Abstract representation of an ImportSystem.
|
||||
* <p>
|
||||
* TODO it is possible to remove the abstract part of this class by binding Importers to a Map with Dagger
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public abstract class ImportSystem implements SubSystem {
|
||||
@Singleton
|
||||
public class ImportSystem implements SubSystem {
|
||||
|
||||
protected final Map<String, Importer> importers;
|
||||
|
||||
protected ImportSystem() {
|
||||
importers = new HashMap<>();
|
||||
@Inject
|
||||
protected ImportSystem(Set<Importer> importers) {
|
||||
this.importers = new HashMap<>();
|
||||
for (Importer importer : importers) {
|
||||
this.importers.put(importer.getName(), importer);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enable() {
|
||||
registerImporters();
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
abstract void registerImporters();
|
||||
|
||||
public void registerImporter(Importer importer) {
|
||||
Verify.nullCheck(importer, () -> new IllegalArgumentException("Importer cannot be null"));
|
||||
|
||||
|
@ -16,17 +16,20 @@
|
||||
*/
|
||||
package com.djrapitops.plan.gathering.timed;
|
||||
|
||||
import com.djrapitops.plan.TaskSystem;
|
||||
import com.djrapitops.plan.gathering.SystemUsage;
|
||||
import com.djrapitops.plan.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.settings.config.paths.DataGatheringSettings;
|
||||
import com.djrapitops.plan.utilities.logging.ErrorContext;
|
||||
import com.djrapitops.plan.utilities.logging.ErrorLogger;
|
||||
import com.djrapitops.plugin.api.TimeAmount;
|
||||
import com.djrapitops.plugin.logging.L;
|
||||
import com.djrapitops.plugin.logging.console.PluginLogger;
|
||||
import com.djrapitops.plugin.task.AbsRunnable;
|
||||
import com.djrapitops.plugin.task.RunnableFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Task for performing system resource usage checks asynchronously
|
||||
@ -64,7 +67,7 @@ public class SystemUsageBuffer {
|
||||
}
|
||||
|
||||
@Singleton
|
||||
public static class RamAndCpuTask extends AbsRunnable {
|
||||
public static class RamAndCpuTask extends TaskSystem.Task {
|
||||
private final SystemUsageBuffer buffer;
|
||||
private final PluginLogger logger;
|
||||
|
||||
@ -84,10 +87,17 @@ public class SystemUsageBuffer {
|
||||
cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(RunnableFactory runnableFactory) {
|
||||
long delay = TimeAmount.toTicks(1, TimeUnit.MINUTES) - TimeAmount.toTicks(500, TimeUnit.MILLISECONDS);
|
||||
long period = TimeAmount.toTicks(1, TimeUnit.SECONDS);
|
||||
runnableFactory.create(null, this).runTaskTimerAsynchronously(delay, period);
|
||||
}
|
||||
}
|
||||
|
||||
@Singleton
|
||||
public static class DiskTask extends AbsRunnable {
|
||||
public static class DiskTask extends TaskSystem.Task {
|
||||
private final PlanConfig config;
|
||||
private final SystemUsageBuffer buffer;
|
||||
private final PluginLogger logger;
|
||||
@ -121,6 +131,13 @@ public class SystemUsageBuffer {
|
||||
cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(RunnableFactory runnableFactory) {
|
||||
long delay = TimeAmount.toTicks(50, TimeUnit.SECONDS);
|
||||
long period = TimeAmount.toTicks(1, TimeUnit.SECONDS);
|
||||
runnableFactory.create(null, this).runTaskTimerAsynchronously(delay, period);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -16,18 +16,22 @@
|
||||
*/
|
||||
package com.djrapitops.plan.gathering.timed;
|
||||
|
||||
import com.djrapitops.plan.TaskSystem;
|
||||
import com.djrapitops.plan.utilities.logging.ErrorContext;
|
||||
import com.djrapitops.plan.utilities.logging.ErrorLogger;
|
||||
import com.djrapitops.plugin.api.TimeAmount;
|
||||
import com.djrapitops.plugin.logging.L;
|
||||
import com.djrapitops.plugin.logging.console.PluginLogger;
|
||||
import com.djrapitops.plugin.task.AbsRunnable;
|
||||
import com.djrapitops.plugin.task.RunnableFactory;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Class responsible for calculating TPS every second.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public abstract class TPSCounter extends AbsRunnable {
|
||||
public abstract class TPSCounter extends TaskSystem.Task {
|
||||
|
||||
protected final PluginLogger logger;
|
||||
protected final ErrorLogger errorLogger;
|
||||
@ -51,6 +55,12 @@ public abstract class TPSCounter extends AbsRunnable {
|
||||
}
|
||||
}
|
||||
|
||||
public void register(RunnableFactory runnableFactory) {
|
||||
long delay = TimeAmount.toTicks(1L, TimeUnit.MINUTES);
|
||||
long period = TimeAmount.toTicks(1L, TimeUnit.SECONDS);
|
||||
runnableFactory.create(null, this).runTaskTimer(delay, period);
|
||||
}
|
||||
|
||||
public abstract void pulse();
|
||||
|
||||
}
|
||||
|
@ -30,16 +30,18 @@ public class Server implements Comparable<Server> {
|
||||
private Integer id;
|
||||
private String name;
|
||||
private String webAddress;
|
||||
private boolean proxy;
|
||||
|
||||
public Server(UUID uuid, String name, String webAddress) {
|
||||
this(null, uuid, name, webAddress);
|
||||
this(null, uuid, name, webAddress, false);
|
||||
}
|
||||
|
||||
public Server(Integer id, UUID uuid, String name, String webAddress) {
|
||||
public Server(Integer id, UUID uuid, String name, String webAddress, boolean proxy) {
|
||||
this.id = id;
|
||||
this.uuid = uuid;
|
||||
this.name = name;
|
||||
this.webAddress = webAddress;
|
||||
this.proxy = proxy;
|
||||
}
|
||||
|
||||
public Optional<Integer> getId() {
|
||||
@ -105,7 +107,11 @@ public class Server implements Comparable<Server> {
|
||||
}
|
||||
|
||||
public boolean isProxy() {
|
||||
return "BungeeCord".equals(name);
|
||||
return proxy;
|
||||
}
|
||||
|
||||
public void setProxy(boolean proxy) {
|
||||
this.proxy = proxy;
|
||||
}
|
||||
|
||||
public boolean isNotProxy() {
|
||||
|
@ -72,10 +72,10 @@ public class ServerFileLoader extends Config implements ServerLoader {
|
||||
UUID serverUUID = UUID.fromString(serverUUIDString);
|
||||
String name = config.getNode(PluginSettings.SERVER_NAME.getPath())
|
||||
.map(ConfigNode::getString)
|
||||
.orElse("BungeeCord");
|
||||
.orElse("Proxy");
|
||||
String address = getString("Server.Web_address");
|
||||
|
||||
return Optional.of(new Server(id, serverUUID, name, address));
|
||||
return Optional.of(new Server(id, serverUUID, name, address, false));
|
||||
} catch (IOException e) {
|
||||
throw new EnableException("Failed to read ServerInfoFile.yml: " + e.getMessage());
|
||||
}
|
||||
|
@ -17,8 +17,6 @@
|
||||
package com.djrapitops.plan.modules;
|
||||
|
||||
import com.djrapitops.plan.gathering.ServerSensor;
|
||||
import com.djrapitops.plan.gathering.importing.EmptyImportSystem;
|
||||
import com.djrapitops.plan.gathering.importing.ImportSystem;
|
||||
import com.djrapitops.plan.settings.ConfigSystem;
|
||||
import com.djrapitops.plan.settings.ProxyConfigSystem;
|
||||
import com.djrapitops.plan.storage.database.DBSystem;
|
||||
@ -40,9 +38,6 @@ public interface ProxySuperClassBindingModule {
|
||||
@Binds
|
||||
ConfigSystem bindConfigSystem(ProxyConfigSystem configSystem);
|
||||
|
||||
@Binds
|
||||
ImportSystem bindImportSystem(EmptyImportSystem emptyImportSystem);
|
||||
|
||||
@Binds
|
||||
ServerSensor<?> bindServerSensor(ServerSensor<Object> sensor);
|
||||
|
||||
|
@ -16,7 +16,10 @@
|
||||
*/
|
||||
package com.djrapitops.plan.modules;
|
||||
|
||||
import com.djrapitops.plan.DataService;
|
||||
import com.djrapitops.plan.DataSvc;
|
||||
import com.djrapitops.plan.PlanPlugin;
|
||||
import com.djrapitops.plan.gathering.importing.importers.Importer;
|
||||
import com.djrapitops.plan.settings.config.ExtensionSettings;
|
||||
import com.djrapitops.plan.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.settings.locale.Locale;
|
||||
@ -26,10 +29,13 @@ import com.djrapitops.plan.utilities.logging.ErrorLogger;
|
||||
import com.djrapitops.plan.utilities.logging.PluginErrorLogger;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import dagger.multibindings.ElementsIntoSet;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
import java.io.File;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
@ -40,6 +46,12 @@ import java.util.function.Predicate;
|
||||
@Module
|
||||
public class SystemObjectProvidingModule {
|
||||
|
||||
@Provides
|
||||
@ElementsIntoSet
|
||||
Set<Importer> emptyImporterSet() {
|
||||
return new HashSet<>();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
Locale provideLocale(LocaleSystem localeSystem) {
|
||||
@ -78,4 +90,10 @@ public class SystemObjectProvidingModule {
|
||||
return errorLogger;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
DataService provideDataService(DataSvc dataService) {
|
||||
return dataService;
|
||||
}
|
||||
|
||||
}
|
@ -62,6 +62,6 @@ public class PlayerKillProcessor implements CriticalRunnable {
|
||||
}
|
||||
Session session = cachedSession.get();
|
||||
|
||||
session.playerKilled(new PlayerKill(victim, weaponName, time));
|
||||
session.playerKilled(new PlayerKill(killer, victim, weaponName, time));
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,6 @@ package com.djrapitops.plan.settings;
|
||||
import com.djrapitops.plan.settings.config.ConfigReader;
|
||||
import com.djrapitops.plan.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.settings.config.changes.ConfigUpdater;
|
||||
import com.djrapitops.plan.settings.config.paths.DatabaseSettings;
|
||||
import com.djrapitops.plan.settings.config.paths.PluginSettings;
|
||||
import com.djrapitops.plan.settings.network.ServerSettingsManager;
|
||||
import com.djrapitops.plan.settings.theme.Theme;
|
||||
@ -43,7 +42,6 @@ public class NukkitConfigSystem extends ConfigSystem {
|
||||
|
||||
private final ConfigUpdater configUpdater;
|
||||
private final ServerSettingsManager serverSettingsManager;
|
||||
private boolean firstInstall;
|
||||
|
||||
@Inject
|
||||
public NukkitConfigSystem(
|
||||
@ -62,7 +60,6 @@ public class NukkitConfigSystem extends ConfigSystem {
|
||||
|
||||
@Override
|
||||
public void enable() {
|
||||
firstInstall = !files.getConfigFile().exists();
|
||||
super.enable();
|
||||
if (config.isTrue(PluginSettings.PROXY_COPY_CONFIG)) {
|
||||
serverSettingsManager.enable();
|
||||
@ -81,10 +78,5 @@ public class NukkitConfigSystem extends ConfigSystem {
|
||||
try (ConfigReader reader = new ConfigReader(files.getResourceFromJar("config.yml").asInputStream())) {
|
||||
config.copyMissing(reader.read());
|
||||
}
|
||||
String dbType = config.get(DatabaseSettings.TYPE);
|
||||
if ("sqlite".equalsIgnoreCase(dbType)) {
|
||||
if (!firstInstall) logger.warn("'SQLite' is not supported on Nukkit, switching to 'H2'.");
|
||||
config.set(DatabaseSettings.TYPE, "H2");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -115,7 +115,7 @@ public enum CommandLang implements Lang {
|
||||
RELOAD_COMPLETE("Cmd Info - Reload Complete", "§aReload Complete"),
|
||||
RELOAD_FAILED("Cmd Info - Reload Failed", "§cSomething went wrong during reload of the plugin, a restart is recommended."),
|
||||
NO_ADDRESS_NOTIFY("Cmd Notify - No Address", "§eNo address was available - using localhost as fallback. Set up 'Alternative_IP' settings."),
|
||||
HOTSWAP_REMINDER("Manage - Remind HotSwap", "§eRemember to swap to the new database (/plan m hotswap ${0}) & reload the plugin."),
|
||||
HOTSWAP_REMINDER("Manage - Remind HotSwap", "§eRemember to swap to the new database (/plan db hotswap ${0}) & reload the plugin."),
|
||||
PROGRESS_START("Manage - Start", "> §2Processing data.."),
|
||||
PROGRESS("Manage - Progress", "${0} / ${1} processed.."),
|
||||
PROGRESS_SUCCESS("Manage - Success", "> §aSuccess!"),
|
||||
|
@ -25,6 +25,7 @@ public enum JSLang implements Lang {
|
||||
|
||||
TEXT_PREDICTED_RETENTION("This value is a prediction based on previous players"),
|
||||
TEXT_NO_SERVERS("No servers found in the database"),
|
||||
TEXT_SERVER_INSTRUCTIONS("It appears that Plan is not installed on any game servers or not connected to the same database. See <a href=\"https://github.com/plan-player-analytics/Plan/wiki\">wiki</a> for Network tutorial."),
|
||||
TEXT_NO_SERVER("No server to display online activity for"),
|
||||
LABEL_REGISTERED_PLAYERS("Registered Players"),
|
||||
LINK_SERVER_ANALYSIS("Server Analysis"),
|
||||
|
@ -17,7 +17,6 @@
|
||||
package com.djrapitops.plan.settings.network;
|
||||
|
||||
import com.djrapitops.plan.SubSystem;
|
||||
import com.djrapitops.plan.TaskSystem;
|
||||
import com.djrapitops.plan.identification.ServerInfo;
|
||||
import com.djrapitops.plan.settings.config.Config;
|
||||
import com.djrapitops.plan.settings.config.ConfigReader;
|
||||
@ -35,6 +34,7 @@ import com.djrapitops.plan.utilities.logging.ErrorLogger;
|
||||
import com.djrapitops.plugin.api.TimeAmount;
|
||||
import com.djrapitops.plugin.logging.console.PluginLogger;
|
||||
import com.djrapitops.plugin.task.AbsRunnable;
|
||||
import com.djrapitops.plugin.task.RunnableFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
@ -62,8 +62,8 @@ public class ServerSettingsManager implements SubSystem {
|
||||
private final PlanConfig config;
|
||||
private final DBSystem dbSystem;
|
||||
private final ServerInfo serverInfo;
|
||||
private final TaskSystem taskSystem;
|
||||
private final ErrorLogger errorLogger;
|
||||
private final RunnableFactory runnableFactory;
|
||||
private final PluginLogger logger;
|
||||
private FileWatcher watcher;
|
||||
|
||||
@ -73,7 +73,7 @@ public class ServerSettingsManager implements SubSystem {
|
||||
PlanConfig config,
|
||||
DBSystem dbSystem,
|
||||
ServerInfo serverInfo,
|
||||
TaskSystem taskSystem,
|
||||
RunnableFactory runnableFactory,
|
||||
PluginLogger logger,
|
||||
ErrorLogger errorLogger
|
||||
) {
|
||||
@ -81,7 +81,7 @@ public class ServerSettingsManager implements SubSystem {
|
||||
this.config = config;
|
||||
this.dbSystem = dbSystem;
|
||||
this.serverInfo = serverInfo;
|
||||
this.taskSystem = taskSystem;
|
||||
this.runnableFactory = runnableFactory;
|
||||
this.logger = logger;
|
||||
this.errorLogger = errorLogger;
|
||||
}
|
||||
@ -125,7 +125,8 @@ public class ServerSettingsManager implements SubSystem {
|
||||
|
||||
private void scheduleDBCheckTask() {
|
||||
long checkPeriod = TimeAmount.toTicks(config.get(TimeSettings.CONFIG_UPDATE_INTERVAL), TimeUnit.MILLISECONDS);
|
||||
taskSystem.registerTask("Config Update DB Checker", new AbsRunnable() {
|
||||
|
||||
runnableFactory.create("Config Update DB Checker", new AbsRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
checkDBForNewConfigSettings(dbSystem.getDatabase());
|
||||
|
@ -16,16 +16,20 @@
|
||||
*/
|
||||
package com.djrapitops.plan.settings.upkeep;
|
||||
|
||||
import com.djrapitops.plan.TaskSystem;
|
||||
import com.djrapitops.plan.identification.ServerInfo;
|
||||
import com.djrapitops.plan.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.settings.config.paths.TimeSettings;
|
||||
import com.djrapitops.plan.storage.database.DBSystem;
|
||||
import com.djrapitops.plan.storage.database.transactions.StoreConfigTransaction;
|
||||
import com.djrapitops.plan.storage.file.PlanFiles;
|
||||
import com.djrapitops.plugin.api.TimeAmount;
|
||||
import com.djrapitops.plugin.logging.console.PluginLogger;
|
||||
import com.djrapitops.plugin.task.AbsRunnable;
|
||||
import com.djrapitops.plugin.task.RunnableFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Task that stores a server config in the database on boot.
|
||||
@ -33,7 +37,7 @@ import javax.inject.Singleton;
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Singleton
|
||||
public class ConfigStoreTask extends AbsRunnable {
|
||||
public class ConfigStoreTask extends TaskSystem.Task {
|
||||
|
||||
private final PlanFiles files;
|
||||
private final PlanConfig config;
|
||||
@ -63,4 +67,10 @@ public class ConfigStoreTask extends AbsRunnable {
|
||||
logger.debug("Config Store Task - Config in db now up to date.");
|
||||
cancel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(RunnableFactory runnableFactory) {
|
||||
long delay = TimeAmount.toTicks(config.get(TimeSettings.CONFIG_UPDATE_INTERVAL), TimeUnit.MILLISECONDS) + 40;
|
||||
runnableFactory.create(null, this).runTaskLaterAsynchronously(delay);
|
||||
}
|
||||
}
|
@ -16,13 +16,18 @@
|
||||
*/
|
||||
package com.djrapitops.plan.settings.upkeep;
|
||||
|
||||
import com.djrapitops.plan.TaskSystem;
|
||||
import com.djrapitops.plan.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.settings.config.paths.TimeSettings;
|
||||
import com.djrapitops.plan.settings.network.NetworkSettingManager;
|
||||
import com.djrapitops.plugin.task.AbsRunnable;
|
||||
import com.djrapitops.plugin.api.TimeAmount;
|
||||
import com.djrapitops.plugin.task.RunnableFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.io.File;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Task on networks that stores server configs in /plugins/Plan/serverConfiguration in database on boot.
|
||||
@ -30,14 +35,17 @@ import java.util.UUID;
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Singleton
|
||||
public class NetworkConfigStoreTask extends AbsRunnable {
|
||||
public class NetworkConfigStoreTask extends TaskSystem.Task {
|
||||
|
||||
private final NetworkSettingManager networkSettingManager;
|
||||
private final PlanConfig config;
|
||||
|
||||
@Inject
|
||||
public NetworkConfigStoreTask(
|
||||
PlanConfig config,
|
||||
NetworkSettingManager networkSettingManager
|
||||
) {
|
||||
this.config = config;
|
||||
this.networkSettingManager = networkSettingManager;
|
||||
}
|
||||
|
||||
@ -47,6 +55,13 @@ public class NetworkConfigStoreTask extends AbsRunnable {
|
||||
cancel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(RunnableFactory runnableFactory) {
|
||||
long delay = TimeAmount.toTicks(config.get(TimeSettings.CONFIG_UPDATE_INTERVAL), TimeUnit.MILLISECONDS) + 40;
|
||||
|
||||
runnableFactory.create(null, this).runTaskLaterAsynchronously(delay);
|
||||
}
|
||||
|
||||
private void updateDBConfigs() {
|
||||
File[] configFiles = networkSettingManager.getConfigFiles();
|
||||
|
||||
|
@ -99,8 +99,10 @@ public class H2DB extends SQLDB {
|
||||
|
||||
private void startConnectionPingTask() {
|
||||
stopConnectionPingTask();
|
||||
logger.warn("H2 database is going to be deprecated in version 5.2. It is recommended to move to MySQL or SQLite when possible.");
|
||||
logger.warn("! ! ! ---------- ! ! !");
|
||||
logger.warn("H2 database is DEPRECATED and WILL STOP WORKING in version 5.4 - It is recommended to move to MySQL or SQLite when possible.");
|
||||
logger.warn("See https://github.com/plan-player-analytics/Plan/issues/1472 for details");
|
||||
logger.warn("! ! ! ---------- ! ! !");
|
||||
try {
|
||||
// Maintains Connection.
|
||||
connectionPingTask = runnableFactory.create("DBConnectionPingTask " + getType().getName(),
|
||||
|
@ -94,7 +94,7 @@ public class MySQLDB extends SQLDB {
|
||||
String database = config.get(DatabaseSettings.MYSQL_DATABASE);
|
||||
String launchOptions = config.get(DatabaseSettings.MYSQL_LAUNCH_OPTIONS);
|
||||
// REGEX: match "?", match "word=word&" *-times, match "word=word"
|
||||
if (launchOptions.isEmpty() || !launchOptions.matches("\\?((\\w*=\\w*)&)*(\\w*=\\w*)")) {
|
||||
if (launchOptions.isEmpty() || !launchOptions.matches("\\?(((\\w|[-])+=.+)&)*((\\w|[-])+=.+)")) {
|
||||
launchOptions = "?rewriteBatchedStatements=true&useSSL=false";
|
||||
logger.error(locale.getString(PluginLang.DB_MYSQL_LAUNCH_OPTIONS_FAIL, launchOptions));
|
||||
}
|
||||
|
@ -173,7 +173,8 @@ public abstract class SQLDB extends AbstractDatabase {
|
||||
new BadNukkitRegisterValuePatch(),
|
||||
new LinkedToSecurityTablePatch(),
|
||||
new LinkUsersToPlayersSecurityTablePatch(),
|
||||
new LitebansTableHeaderPatch()
|
||||
new LitebansTableHeaderPatch(),
|
||||
new ServerIsProxyPatch()
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -151,19 +151,17 @@ public class LargeStoreQueries {
|
||||
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();
|
||||
|
||||
for (Server server : servers) {
|
||||
UUID uuid = server.getUuid();
|
||||
if (uuid == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
statement.setString(1, uuid.toString());
|
||||
statement.setString(2, name);
|
||||
statement.setString(3, webAddress);
|
||||
statement.setString(2, server.getName());
|
||||
statement.setString(3, server.getWebAddress());
|
||||
statement.setBoolean(4, true);
|
||||
statement.setBoolean(5, server.isProxy());
|
||||
statement.addBatch();
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,9 @@ public class KillQueries {
|
||||
}
|
||||
|
||||
public static Query<List<PlayerKill>> fetchPlayerKillsOnServer(UUID serverUUID, int limit) {
|
||||
String sql = SELECT + KillsTable.VICTIM_UUID + ", " +
|
||||
String sql = SELECT +
|
||||
KillsTable.KILLER_UUID + ", " +
|
||||
KillsTable.VICTIM_UUID + ", " +
|
||||
"v." + UsersTable.USER_NAME + " as victim_name, " +
|
||||
"k." + UsersTable.USER_NAME + " as killer_name," +
|
||||
KillsTable.DATE + ", " +
|
||||
@ -76,7 +78,9 @@ public class KillQueries {
|
||||
}
|
||||
|
||||
public static Query<List<PlayerKill>> fetchPlayerKillsOfPlayer(UUID playerUUID) {
|
||||
String sql = SELECT + KillsTable.VICTIM_UUID + ", " +
|
||||
String sql = SELECT +
|
||||
KillsTable.KILLER_UUID + ", " +
|
||||
KillsTable.VICTIM_UUID + ", " +
|
||||
"v." + UsersTable.USER_NAME + " as victim_name, " +
|
||||
"k." + UsersTable.USER_NAME + " as killer_name," +
|
||||
KillsTable.DATE + ", " +
|
||||
@ -105,7 +109,9 @@ public class KillQueries {
|
||||
}
|
||||
|
||||
public static Query<List<PlayerKill>> fetchPlayerDeathsOfPlayer(UUID playerUUID) {
|
||||
String sql = SELECT + KillsTable.VICTIM_UUID + ", " +
|
||||
String sql = SELECT +
|
||||
KillsTable.KILLER_UUID + ", " +
|
||||
KillsTable.VICTIM_UUID + ", " +
|
||||
"v." + UsersTable.USER_NAME + " as victim_name, " +
|
||||
"k." + UsersTable.USER_NAME + " as killer_name," +
|
||||
KillsTable.DATE + ", " +
|
||||
@ -137,10 +143,11 @@ public class KillQueries {
|
||||
String victimName = set.getString("victim_name");
|
||||
String killerName = set.getString("killer_name");
|
||||
if (victimName != null && killerName != null) {
|
||||
UUID killer = UUID.fromString(set.getString(KillsTable.KILLER_UUID));
|
||||
UUID victim = UUID.fromString(set.getString(KillsTable.VICTIM_UUID));
|
||||
long date = set.getLong(KillsTable.DATE);
|
||||
String weapon = set.getString(KillsTable.WEAPON);
|
||||
return Optional.of(new PlayerKill(victim, weapon, date, victimName, killerName));
|
||||
return Optional.of(new PlayerKill(killer, victim, weapon, date, victimName, killerName));
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
@ -65,7 +65,9 @@ public class ServerQueries {
|
||||
set.getInt(ServerTable.SERVER_ID),
|
||||
serverUUID,
|
||||
set.getString(ServerTable.NAME),
|
||||
set.getString(ServerTable.WEB_ADDRESS)));
|
||||
set.getString(ServerTable.WEB_ADDRESS),
|
||||
set.getBoolean(ServerTable.PROXY)
|
||||
));
|
||||
}
|
||||
return servers;
|
||||
}
|
||||
@ -106,7 +108,8 @@ public class ServerQueries {
|
||||
set.getInt(ServerTable.SERVER_ID),
|
||||
UUID.fromString(set.getString(ServerTable.SERVER_UUID)),
|
||||
set.getString(ServerTable.NAME),
|
||||
set.getString(ServerTable.WEB_ADDRESS)
|
||||
set.getString(ServerTable.WEB_ADDRESS),
|
||||
set.getBoolean(ServerTable.PROXY)
|
||||
));
|
||||
}
|
||||
return Optional.empty();
|
||||
@ -115,7 +118,31 @@ public class ServerQueries {
|
||||
}
|
||||
|
||||
public static Query<Optional<Server>> fetchProxyServerInformation() {
|
||||
return db -> db.query(fetchServerMatchingIdentifier("BungeeCord"));
|
||||
String sql = SELECT + '*' + FROM + ServerTable.TABLE_NAME +
|
||||
WHERE + ServerTable.INSTALLED + "=?" +
|
||||
AND + ServerTable.PROXY + "=?" +
|
||||
" LIMIT 1";
|
||||
return new QueryStatement<Optional<Server>>(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setBoolean(1, true);
|
||||
statement.setBoolean(2, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Server> processResults(ResultSet set) throws SQLException {
|
||||
if (set.next()) {
|
||||
return Optional.of(new Server(
|
||||
set.getInt(ServerTable.SERVER_ID),
|
||||
UUID.fromString(set.getString(ServerTable.SERVER_UUID)),
|
||||
set.getString(ServerTable.NAME),
|
||||
set.getString(ServerTable.WEB_ADDRESS),
|
||||
set.getBoolean(ServerTable.PROXY)
|
||||
));
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Query<Map<UUID, String>> fetchServerNames() {
|
||||
@ -165,11 +192,44 @@ public class ServerQueries {
|
||||
set.getInt(ServerTable.SERVER_ID),
|
||||
UUID.fromString(set.getString(ServerTable.SERVER_UUID)),
|
||||
set.getString(ServerTable.NAME),
|
||||
set.getString(ServerTable.WEB_ADDRESS)
|
||||
set.getString(ServerTable.WEB_ADDRESS),
|
||||
set.getBoolean(ServerTable.PROXY)
|
||||
));
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Query<Integer> fetchServerCount() {
|
||||
String sql = SELECT + "COUNT(1) as c" + FROM + ServerTable.TABLE_NAME +
|
||||
WHERE + ServerTable.INSTALLED + "=?";
|
||||
return new QueryStatement<Integer>(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setBoolean(1, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer processResults(ResultSet set) throws SQLException {
|
||||
return set.next() ? set.getInt("c") : 1;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Query<Integer> fetchBiggestServerID() {
|
||||
String sql = SELECT + "MAX(" + ServerTable.SERVER_ID + ") as max_id" + FROM + ServerTable.TABLE_NAME +
|
||||
WHERE + ServerTable.INSTALLED + "=?";
|
||||
return new QueryStatement<Integer>(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setBoolean(1, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer processResults(ResultSet set) throws SQLException {
|
||||
return set.next() ? set.getInt("max_id") : 1;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -67,6 +67,7 @@ public class SessionQueries {
|
||||
WorldTimesTable.ADVENTURE + ',' +
|
||||
WorldTimesTable.SPECTATOR + ',' +
|
||||
WorldTable.NAME + ',' +
|
||||
KillsTable.KILLER_UUID + ',' +
|
||||
KillsTable.VICTIM_UUID + ',' +
|
||||
"v." + UsersTable.USER_NAME + " as victim_name, " +
|
||||
KillsTable.DATE + ',' +
|
||||
@ -193,11 +194,12 @@ public class SessionQueries {
|
||||
|
||||
String victimName = set.getString("victim_name");
|
||||
if (victimName != null) {
|
||||
UUID killer = UUID.fromString(set.getString(KillsTable.KILLER_UUID));
|
||||
UUID victim = UUID.fromString(set.getString(KillsTable.VICTIM_UUID));
|
||||
long date = set.getLong(KillsTable.DATE);
|
||||
String weapon = set.getString(KillsTable.WEAPON);
|
||||
List<PlayerKill> playerKills = session.getPlayerKills();
|
||||
PlayerKill newKill = new PlayerKill(victim, weapon, date, victimName);
|
||||
PlayerKill newKill = new PlayerKill(killer, victim, weapon, date, victimName);
|
||||
if (!playerKills.contains(newKill)) {
|
||||
playerKills.add(newKill);
|
||||
}
|
||||
|
@ -40,18 +40,20 @@ public class ServerTable {
|
||||
public static final String NAME = "name";
|
||||
public static final String WEB_ADDRESS = "web_address";
|
||||
public static final String INSTALLED = "is_installed";
|
||||
public static final String PROXY = "is_proxy";
|
||||
@Deprecated
|
||||
public static final String MAX_PLAYERS = "max_players";
|
||||
|
||||
public static final String INSERT_STATEMENT = Insert.values(TABLE_NAME,
|
||||
SERVER_UUID, NAME,
|
||||
WEB_ADDRESS, INSTALLED);
|
||||
WEB_ADDRESS, INSTALLED, PROXY);
|
||||
|
||||
public static final String UPDATE_STATEMENT = Update.values(TABLE_NAME,
|
||||
SERVER_UUID,
|
||||
NAME,
|
||||
WEB_ADDRESS,
|
||||
INSTALLED)
|
||||
INSTALLED,
|
||||
PROXY)
|
||||
.where(SERVER_UUID + "=?")
|
||||
.toString();
|
||||
|
||||
@ -71,6 +73,7 @@ public class ServerTable {
|
||||
.column(NAME, Sql.varchar(100))
|
||||
.column(WEB_ADDRESS, Sql.varchar(100))
|
||||
.column(INSTALLED, Sql.BOOL).notNull().defaultValue(true)
|
||||
.column(PROXY, Sql.BOOL).notNull().defaultValue(false)
|
||||
.column(MAX_PLAYERS, Sql.INT).notNull().defaultValue("-1")
|
||||
.toString();
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ import static com.djrapitops.plan.storage.database.sql.tables.ServerTable.INSERT
|
||||
import static com.djrapitops.plan.storage.database.sql.tables.ServerTable.UPDATE_STATEMENT;
|
||||
|
||||
/**
|
||||
* Transaction for keeping Plan Server serverrmation up to date in the database.
|
||||
* Transaction for keeping Plan Server information up to date in the database.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@ -53,7 +53,8 @@ public class StoreServerInformationTransaction extends Transaction {
|
||||
statement.setString(2, server.getName());
|
||||
statement.setString(3, server.getWebAddress());
|
||||
statement.setBoolean(4, true);
|
||||
statement.setString(5, serverUUIDString);
|
||||
statement.setBoolean(5, server.isProxy());
|
||||
statement.setString(6, serverUUIDString);
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -66,6 +67,7 @@ public class StoreServerInformationTransaction extends Transaction {
|
||||
statement.setString(2, server.getName());
|
||||
statement.setString(3, server.getWebAddress());
|
||||
statement.setBoolean(4, true);
|
||||
statement.setBoolean(5, server.isProxy());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -16,7 +16,6 @@
|
||||
*/
|
||||
package com.djrapitops.plan.storage.database.transactions.commands;
|
||||
|
||||
import com.djrapitops.plan.delivery.domain.WebUser;
|
||||
import com.djrapitops.plan.delivery.webserver.auth.ActiveCookieStore;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.WebUserQueries;
|
||||
import com.djrapitops.plan.storage.database.sql.tables.SecurityTable;
|
||||
@ -30,7 +29,7 @@ import static com.djrapitops.plan.storage.database.sql.building.Sql.DELETE_FROM;
|
||||
import static com.djrapitops.plan.storage.database.sql.building.Sql.WHERE;
|
||||
|
||||
/**
|
||||
* Transaction to remove a Plan {@link WebUser} from the database.
|
||||
* Transaction to remove a Plan {@link com.djrapitops.plan.delivery.domain.auth.User} from the database.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
|
@ -18,6 +18,8 @@ package com.djrapitops.plan.storage.database.transactions.patches;
|
||||
|
||||
/**
|
||||
* Patch that removes plan_commandusages table.
|
||||
* <p>
|
||||
* See https://github.com/plan-player-analytics/Plan/issues/1240 for more details
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
|
@ -26,6 +26,8 @@ import static com.djrapitops.plan.storage.database.sql.building.Sql.*;
|
||||
|
||||
/**
|
||||
* Patch that replaces plan_ips with plan_geolocations table.
|
||||
* <p>
|
||||
* Prepares Plan to be GDPR compliant through the easiest to make change.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
|
@ -18,6 +18,11 @@ package com.djrapitops.plan.storage.database.transactions.patches;
|
||||
|
||||
import com.djrapitops.plan.storage.database.sql.tables.TPSTable;
|
||||
|
||||
/**
|
||||
* Adds disk usage information to tps table.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class DiskUsagePatch extends Patch {
|
||||
|
||||
@Override
|
||||
|
@ -23,6 +23,11 @@ import com.djrapitops.plan.storage.database.sql.building.Sql;
|
||||
import com.djrapitops.plan.storage.database.sql.tables.ExtensionPlayerTableValueTable;
|
||||
import com.djrapitops.plan.storage.database.sql.tables.ExtensionServerTableValueTable;
|
||||
|
||||
/**
|
||||
* Increases the length of Strings in extension tables to 250 to avoid cutoffs and exceptions.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class ExtensionTableRowValueLengthPatch extends Patch {
|
||||
|
||||
private final String playerTable;
|
||||
|
@ -18,6 +18,11 @@ package com.djrapitops.plan.storage.database.transactions.patches;
|
||||
|
||||
import com.djrapitops.plan.storage.database.sql.tables.GeoInfoTable;
|
||||
|
||||
/**
|
||||
* Adds last_used field to the geolocation table.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class GeoInfoLastUsedPatch extends Patch {
|
||||
|
||||
@Override
|
||||
|
@ -20,6 +20,11 @@ import com.djrapitops.plan.storage.database.sql.tables.GeoInfoTable;
|
||||
|
||||
import static com.djrapitops.plan.storage.database.sql.building.Sql.*;
|
||||
|
||||
/**
|
||||
* Replaces user_id foreign keys with user_uuid fields in geolocation table.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class GeoInfoOptimizationPatch extends Patch {
|
||||
|
||||
private final String tempTableName;
|
||||
|
@ -21,6 +21,13 @@ import com.djrapitops.plan.storage.database.sql.tables.KillsTable;
|
||||
|
||||
import static com.djrapitops.plan.storage.database.sql.building.Sql.FROM;
|
||||
|
||||
/**
|
||||
* Replaces killer_id, victim_id and server_id foreign keys with respective uuid fields in kills table.
|
||||
* <p>
|
||||
* This was to "reduce the amount of joins when querying sessions".
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class KillsOptimizationPatch extends Patch {
|
||||
|
||||
private final String tempTableName;
|
||||
|
@ -24,6 +24,14 @@ import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Adds server_id field to kills table.
|
||||
* <p>
|
||||
* The field is populated by querying the session table for server ids.
|
||||
*
|
||||
* @author Rsl1122
|
||||
* @see KillsOptimizationPatch for removal of this field later
|
||||
*/
|
||||
public class KillsServerIDPatch extends Patch {
|
||||
|
||||
@Override
|
||||
|
@ -31,6 +31,12 @@ import java.util.Map;
|
||||
|
||||
import static com.djrapitops.plan.storage.database.sql.building.Sql.*;
|
||||
|
||||
/**
|
||||
* Populates new linked_to_uuid field with the uuid of a username (same as minecraft name) or 'console'.
|
||||
*
|
||||
* @author Rsl1122
|
||||
* @see LinkedToSecurityTablePatch for addition of the field.
|
||||
*/
|
||||
public class LinkUsersToPlayersSecurityTablePatch extends Patch {
|
||||
|
||||
@Override
|
||||
|
@ -19,6 +19,14 @@ package com.djrapitops.plan.storage.database.transactions.patches;
|
||||
import com.djrapitops.plan.storage.database.sql.building.Sql;
|
||||
import com.djrapitops.plan.storage.database.sql.tables.SecurityTable;
|
||||
|
||||
/**
|
||||
* Adds linked_to_uuid field to plan_security table that stores web users.
|
||||
* <p>
|
||||
* This patch allows web users to have a username other than the minecraft username.
|
||||
*
|
||||
* @author Rsl1122
|
||||
* @see LinkUsersToPlayersSecurityTablePatch for the patch that populates the field afterwards.
|
||||
*/
|
||||
public class LinkedToSecurityTablePatch extends Patch {
|
||||
|
||||
@Override
|
||||
|
@ -35,6 +35,13 @@ import java.util.UUID;
|
||||
import static com.djrapitops.plan.storage.database.sql.building.Sql.AND;
|
||||
import static com.djrapitops.plan.storage.database.sql.building.Sql.WHERE;
|
||||
|
||||
/**
|
||||
* Adds last_seen to nickname table by populating it with the data in actions table, and removes the actions table.
|
||||
* <p>
|
||||
* Actions table contained nickname change events and change to "last seen" saved space on the interface.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class NicknameLastSeenPatch extends Patch {
|
||||
|
||||
@Override
|
||||
|
@ -21,6 +21,13 @@ import com.djrapitops.plan.storage.database.sql.tables.NicknamesTable;
|
||||
|
||||
import static com.djrapitops.plan.storage.database.sql.building.Sql.FROM;
|
||||
|
||||
/**
|
||||
* Replaces user_id and server_id foreign keys with respective uuid fields in nickname table.
|
||||
* <p>
|
||||
* This was to "reduce the amount of joins when querying sessions".
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class NicknamesOptimizationPatch extends Patch {
|
||||
|
||||
private final String tempTableName;
|
||||
|
@ -21,6 +21,11 @@ import com.djrapitops.plan.storage.database.sql.tables.PingTable;
|
||||
|
||||
import static com.djrapitops.plan.storage.database.sql.building.Sql.FROM;
|
||||
|
||||
/**
|
||||
* Replaces user_id and server_id foreign keys with respective uuid fields in ping table.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class PingOptimizationPatch extends Patch {
|
||||
|
||||
private final String tempTableName;
|
||||
|
@ -31,6 +31,15 @@ import java.util.UUID;
|
||||
|
||||
import static com.djrapitops.plan.storage.database.sql.building.Sql.*;
|
||||
|
||||
/**
|
||||
* Changes register dates on networks to the smallest number found in the database.
|
||||
* <p>
|
||||
* Proxy servers do not store player register date information, so Game servers can hold earlier
|
||||
* join date than the first session Plan sees. This patch changes the register date in
|
||||
* plan_users if a smaller register date in plan_user_info is found.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class RegisterDateMinimizationPatch extends Patch {
|
||||
|
||||
private Map<UUID, Long> registerDates;
|
||||
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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.storage.database.transactions.patches;
|
||||
|
||||
import com.djrapitops.plan.storage.database.sql.building.Sql;
|
||||
import com.djrapitops.plan.storage.database.sql.tables.ServerTable;
|
||||
import com.djrapitops.plan.storage.database.transactions.ExecStatement;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import static com.djrapitops.plan.storage.database.sql.building.Sql.WHERE;
|
||||
|
||||
/**
|
||||
* Adds a is_proxy field to remove technical debt assuming name field "BungeeCord" being the proxy.
|
||||
* <p>
|
||||
* See https://github.com/plan-player-analytics/Plan/issues/1678 for more details
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class ServerIsProxyPatch extends Patch {
|
||||
|
||||
@Override
|
||||
public boolean hasBeenApplied() {
|
||||
return hasColumn(ServerTable.TABLE_NAME, ServerTable.PROXY);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyPatch() {
|
||||
addColumn(ServerTable.TABLE_NAME, ServerTable.PROXY + ' ' + Sql.BOOL + " DEFAULT 0");
|
||||
|
||||
String populateFieldSql = "UPDATE " + ServerTable.TABLE_NAME + " SET " + ServerTable.PROXY + "=?" +
|
||||
WHERE + ServerTable.NAME + "=?";
|
||||
execute(new ExecStatement(populateFieldSql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setBoolean(1, true);
|
||||
statement.setString(2, "BungeeCord");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -18,6 +18,11 @@ package com.djrapitops.plan.storage.database.transactions.patches;
|
||||
|
||||
import com.djrapitops.plan.storage.database.sql.tables.SessionsTable;
|
||||
|
||||
/**
|
||||
* Adds afk_time field to sessions table.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class SessionAFKTimePatch extends Patch {
|
||||
|
||||
@Override
|
||||
|
@ -21,6 +21,13 @@ import com.djrapitops.plan.storage.database.sql.tables.SessionsTable;
|
||||
|
||||
import static com.djrapitops.plan.storage.database.sql.building.Sql.FROM;
|
||||
|
||||
/**
|
||||
* Replaces user_id and server_id foreign keys with respective uuid fields in sessions table.
|
||||
* <p>
|
||||
* This was to "reduce the amount of joins when querying sessions".
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class SessionsOptimizationPatch extends Patch {
|
||||
|
||||
private final String tempTableName;
|
||||
|
@ -16,6 +16,13 @@
|
||||
*/
|
||||
package com.djrapitops.plan.storage.database.transactions.patches;
|
||||
|
||||
/**
|
||||
* Removes plan_transfer table, used for transferring html in the database.
|
||||
* <p>
|
||||
* The idea turned out to use a lot of disk space and improper use of a database.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class TransferTableRemovalPatch extends Patch {
|
||||
|
||||
@Override
|
||||
|
@ -21,6 +21,11 @@ import com.djrapitops.plan.storage.database.sql.tables.UserInfoTable;
|
||||
|
||||
import static com.djrapitops.plan.storage.database.sql.building.Sql.FROM;
|
||||
|
||||
/**
|
||||
* Replaces user_id and server_id foreign keys with respective uuid fields in user info table.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class UserInfoOptimizationPatch extends Patch {
|
||||
|
||||
private final String tempTableName;
|
||||
|
@ -24,6 +24,18 @@ import java.util.Optional;
|
||||
|
||||
import static com.djrapitops.plan.storage.database.sql.building.Sql.FROM;
|
||||
|
||||
/**
|
||||
* Table schema change patch for version 4.0.0 to support BungeeCord servers.
|
||||
* <p>
|
||||
* This patch makes the database compatible with further changes to the schema,
|
||||
* bugs in this patch are possible, as the patch is untested against new schema.
|
||||
* <p>
|
||||
* Version 10 comes from "schema version" that was in use in the database to version changes
|
||||
* before Patch system was implemented.
|
||||
*
|
||||
* @author Rsl1122
|
||||
* @see VersionTableRemovalPatch for Patch that removes the schema versions
|
||||
*/
|
||||
public class Version10Patch extends Patch {
|
||||
|
||||
private Integer serverID;
|
||||
|
@ -16,6 +16,11 @@
|
||||
*/
|
||||
package com.djrapitops.plan.storage.database.transactions.patches;
|
||||
|
||||
/**
|
||||
* Removes the table schema versioning table.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class VersionTableRemovalPatch extends Patch {
|
||||
|
||||
@Override
|
||||
|
@ -21,6 +21,13 @@ import com.djrapitops.plan.storage.database.sql.tables.WorldTimesTable;
|
||||
|
||||
import static com.djrapitops.plan.storage.database.sql.building.Sql.FROM;
|
||||
|
||||
/**
|
||||
* Replaces server_id foreign keys with server_uuid field in world times table.
|
||||
* <p>
|
||||
* This was to "reduce the amount of joins when querying sessions".
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class WorldTimesOptimizationPatch extends Patch {
|
||||
|
||||
private final String tempTableName;
|
||||
|
@ -26,6 +26,12 @@ import java.util.Map;
|
||||
|
||||
import static com.djrapitops.plan.storage.database.sql.building.Sql.WHERE;
|
||||
|
||||
/**
|
||||
* Adds server_id field to world times table.
|
||||
*
|
||||
* @author Rsl1122
|
||||
* @see WorldTimesOptimizationPatch for removal of this field later
|
||||
*/
|
||||
public class WorldTimesSeverIDPatch extends Patch {
|
||||
|
||||
@Override
|
||||
|
@ -21,6 +21,13 @@ import com.djrapitops.plan.storage.database.sql.tables.WorldTable;
|
||||
|
||||
import static com.djrapitops.plan.storage.database.sql.building.Sql.FROM;
|
||||
|
||||
/**
|
||||
* Replaces server_id foreign keys with server_uuid field in world table.
|
||||
* <p>
|
||||
* This was to "reduce the amount of joins when querying sessions".
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class WorldsOptimizationPatch extends Patch {
|
||||
|
||||
private final String tempTableName;
|
||||
|
@ -34,6 +34,12 @@ import java.util.stream.Collectors;
|
||||
|
||||
import static com.djrapitops.plan.storage.database.sql.building.Sql.*;
|
||||
|
||||
/**
|
||||
* Adds server_id field to worlds table.
|
||||
*
|
||||
* @author Rsl1122
|
||||
* @see WorldsOptimizationPatch for removal of the field.
|
||||
*/
|
||||
public class WorldsServerIDPatch extends Patch {
|
||||
|
||||
@Override
|
||||
|
@ -16,6 +16,7 @@
|
||||
*/
|
||||
package com.djrapitops.plan.storage.upkeep;
|
||||
|
||||
import com.djrapitops.plan.TaskSystem;
|
||||
import com.djrapitops.plan.exceptions.database.DBOpException;
|
||||
import com.djrapitops.plan.extension.implementation.storage.transactions.results.RemoveUnsatisfiedConditionalPlayerResultsTransaction;
|
||||
import com.djrapitops.plan.extension.implementation.storage.transactions.results.RemoveUnsatisfiedConditionalServerResultsTransaction;
|
||||
@ -29,15 +30,18 @@ import com.djrapitops.plan.storage.database.DBSystem;
|
||||
import com.djrapitops.plan.storage.database.Database;
|
||||
import com.djrapitops.plan.storage.database.queries.Query;
|
||||
import com.djrapitops.plan.storage.database.queries.QueryStatement;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.ServerQueries;
|
||||
import com.djrapitops.plan.storage.database.sql.tables.SessionsTable;
|
||||
import com.djrapitops.plan.storage.database.transactions.commands.RemovePlayerTransaction;
|
||||
import com.djrapitops.plan.storage.database.transactions.init.RemoveDuplicateUserInfoTransaction;
|
||||
import com.djrapitops.plan.storage.database.transactions.init.RemoveOldExtensionsTransaction;
|
||||
import com.djrapitops.plan.storage.database.transactions.init.RemoveOldSampledDataTransaction;
|
||||
import com.djrapitops.plan.utilities.logging.ErrorLogger;
|
||||
import com.djrapitops.plugin.api.TimeAmount;
|
||||
import com.djrapitops.plugin.logging.L;
|
||||
import com.djrapitops.plugin.logging.console.PluginLogger;
|
||||
import com.djrapitops.plugin.task.AbsRunnable;
|
||||
import com.djrapitops.plugin.task.RunnableFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
@ -47,6 +51,7 @@ import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static com.djrapitops.plan.storage.database.sql.building.Sql.*;
|
||||
|
||||
@ -56,7 +61,7 @@ import static com.djrapitops.plan.storage.database.sql.building.Sql.*;
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Singleton
|
||||
public class DBCleanTask extends AbsRunnable {
|
||||
public class DBCleanTask extends TaskSystem.Task {
|
||||
|
||||
private final Locale locale;
|
||||
private final DBSystem dbSystem;
|
||||
@ -97,6 +102,7 @@ public class DBCleanTask extends AbsRunnable {
|
||||
Database database = dbSystem.getDatabase();
|
||||
try {
|
||||
if (database.getState() != Database.State.CLOSED) {
|
||||
|
||||
database.executeTransaction(new RemoveOldSampledDataTransaction(
|
||||
serverInfo.getServerUUID(),
|
||||
config.get(TimeSettings.DELETE_TPS_DATA_AFTER),
|
||||
@ -120,6 +126,30 @@ public class DBCleanTask extends AbsRunnable {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(RunnableFactory runnableFactory) {
|
||||
// Secondary task for registration due to database queries.
|
||||
runnableFactory.create(null, new AbsRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// Distribute clean task evenly between multiple servers.
|
||||
// see https://github.com/plan-player-analytics/Plan/issues/1641 for why
|
||||
Integer biggestId = dbSystem.getDatabase().query(ServerQueries.fetchBiggestServerID());
|
||||
Integer id = serverInfo.getServer().getId().orElse(1);
|
||||
|
||||
double distributor = id * 1.0 / biggestId; // 0 < distributor <= 1
|
||||
long distributingOverTime = config.get(TimeSettings.CLEAN_DATABASE_PERIOD);
|
||||
|
||||
// -40 seconds to start first at 20 seconds if only one server is present.
|
||||
long startAfter = (long) (distributor * distributingOverTime) - 40L;
|
||||
|
||||
long delay = TimeAmount.toTicks(startAfter, TimeUnit.MILLISECONDS);
|
||||
long period = TimeAmount.toTicks(config.get(TimeSettings.CLEAN_DATABASE_PERIOD), TimeUnit.MILLISECONDS);
|
||||
runnableFactory.create(null, this).runTaskTimerAsynchronously(delay, period);
|
||||
}
|
||||
}).runTaskAsynchronously();
|
||||
}
|
||||
|
||||
// VisibleForTesting
|
||||
public int cleanOldPlayers(Database database) {
|
||||
long now = System.currentTimeMillis();
|
||||
|
@ -16,11 +16,13 @@
|
||||
*/
|
||||
package com.djrapitops.plan.storage.upkeep;
|
||||
|
||||
import com.djrapitops.plan.TaskSystem;
|
||||
import com.djrapitops.plan.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.settings.config.paths.PluginSettings;
|
||||
import com.djrapitops.plan.storage.file.PlanFiles;
|
||||
import com.djrapitops.plugin.api.TimeAmount;
|
||||
import com.djrapitops.plugin.logging.console.PluginLogger;
|
||||
import com.djrapitops.plugin.task.AbsRunnable;
|
||||
import com.djrapitops.plugin.task.RunnableFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
@ -36,7 +38,7 @@ import java.util.concurrent.TimeUnit;
|
||||
* @author Rsl1122
|
||||
*/
|
||||
@Singleton
|
||||
public class LogsFolderCleanTask extends AbsRunnable {
|
||||
public class LogsFolderCleanTask extends TaskSystem.Task {
|
||||
|
||||
private final File folder;
|
||||
private final PlanConfig config;
|
||||
@ -71,6 +73,12 @@ public class LogsFolderCleanTask extends AbsRunnable {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(RunnableFactory runnableFactory) {
|
||||
long delay = TimeAmount.toTicks(30L, TimeUnit.SECONDS);
|
||||
runnableFactory.create(null, this).runTaskLaterAsynchronously(delay);
|
||||
}
|
||||
|
||||
private void cleanFolder() {
|
||||
long now = System.currentTimeMillis();
|
||||
for (File file : Objects.requireNonNull(folder.listFiles())) {
|
||||
|
@ -1,35 +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.utilities.comparators;
|
||||
|
||||
import com.djrapitops.plan.delivery.domain.WebUser;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
/**
|
||||
* Orders WebUsers in descending order by permission level.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class WebUserComparator implements Comparator<WebUser> {
|
||||
|
||||
@Override
|
||||
public int compare(WebUser o1, WebUser o2) {
|
||||
return Integer.compare(o2.getPermLevel(), o1.getPermLevel());
|
||||
}
|
||||
|
||||
}
|
@ -398,7 +398,7 @@ Manage - Fail Same server || 无法将服务器标记为
|
||||
Manage - Fail, Confirmation || > §c[数据统计] 请添加 -a 以确认执行!${0}
|
||||
Manage - List Importers || 导入器:
|
||||
Manage - Progress || ${0} / ${1} processed..
|
||||
Manage - Remind HotSwap || §e[数据统计] 请切换至新数据库并重载插件(/plan m hotswap ${0})
|
||||
Manage - Remind HotSwap || §e[数据统计] 请切换至新数据库并重载插件(/plan db hotswap ${0})
|
||||
Manage - Start || »§7 正在处理数据...
|
||||
Manage - Success || §f» §2 成功!
|
||||
Negative || 否
|
||||
|
@ -398,7 +398,7 @@ Manage - Fail Same server || Nelze označit tento server j
|
||||
Manage - Fail, Confirmation || > §cPřidejte '-a' argument k potvrzení provedení: ${0}
|
||||
Manage - List Importers || Importery:
|
||||
Manage - Progress || ${0} / ${1} zpracovávání..
|
||||
Manage - Remind HotSwap || §eNezapomeňte přehodit na novou databázi (/plan m hotswap ${0}) & reload pluginu.
|
||||
Manage - Remind HotSwap || §eNezapomeňte přehodit na novou databázi (/plan db hotswap ${0}) & reload pluginu.
|
||||
Manage - Start || > §2Zpracovávám data..
|
||||
Manage - Success || > §aÚspěch!
|
||||
Negative || Ne
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user