Merge pull request #687 from Rsl1122/cleaning

PR for cleaning to update sonarcloud smells
This commit is contained in:
Rsl1122 2018-08-15 09:59:36 +03:00 committed by GitHub
commit 4078831362
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
98 changed files with 971 additions and 836 deletions

View File

@ -117,7 +117,7 @@ public class Plan extends BukkitPlugin implements PlanPlugin {
@Override
public void onReload() {
// Nothing to be done, systems are disabled
}
@Override
@ -161,6 +161,7 @@ public class Plan extends BukkitPlugin implements PlanPlugin {
throw new IllegalStateException("This method should be used on this plugin.");
}
@Override
public BukkitSystem getSystem() {
return system;
}

View File

@ -80,6 +80,7 @@ public class PlanBungee extends BungeePlugin implements PlanPlugin {
@Override
public void onReload() {
// Nothing to be done, systems are disabled
}
@Override
@ -92,6 +93,7 @@ public class PlanBungee extends BungeePlugin implements PlanPlugin {
return PlanColorScheme.create();
}
@Override
public BungeeSystem getSystem() {
return system;
}

View File

@ -101,7 +101,7 @@ public class PlanSponge extends SpongePlugin implements PlanPlugin {
@Override
public void onReload() {
// Nothing to be done, systems are disabled
}
@Override
@ -124,6 +124,7 @@ public class PlanSponge extends SpongePlugin implements PlanPlugin {
return getClass().getAnnotation(Plugin.class).version();
}
@Override
public SpongeSystem getSystem() {
return system;
}

View File

@ -9,8 +9,6 @@ import java.sql.SQLException;
*/
public class DBOpException extends RuntimeException {
private boolean fatal = false;
public DBOpException(String message) {
super(message);
}
@ -23,11 +21,4 @@ public class DBOpException extends RuntimeException {
return new DBOpException("SQL Failed: " + sql + "; " + e.getMessage(), e);
}
public boolean isFatal() {
return fatal;
}
public void setFatal(boolean fatal) {
this.fatal = fatal;
}
}

View File

@ -49,10 +49,6 @@ public class PlanBungeeCommand extends TreeCmdNode {
new StatusCommand<>(plugin, Permissions.MANAGE.getPermission(), plugin.getColorScheme()),
// (Settings.ALLOW_UPDATE.isTrue() ? new UpdateCommand() : null)
};
setNodeGroups(
analyticsGroup,
webGroup,
manageGroup
);
setNodeGroups(analyticsGroup, webGroup, manageGroup);
}
}

View File

@ -74,11 +74,7 @@ public class InspectCommand extends CommandNode {
checkWebUserAndNotify(activeDB, sender);
Processing.submit(new InspectCacheRequestProcessor(uuid, sender, playerName, locale));
} catch (DBOpException e) {
if (e.isFatal()) {
sender.sendMessage("§cFatal database exception occurred: " + e.getMessage());
} else {
sender.sendMessage("§eNon-Fatal database exception occurred: " + e.getMessage());
}
sender.sendMessage("§eDatabase exception occurred: " + e.getMessage());
Log.toLog(this.getClass(), e);
} finally {
this.cancel();

View File

@ -26,22 +26,22 @@ public class ManageCommand extends TreeCmdNode {
setShortHelp(locale.getString(CmdHelpLang.MANAGE));
setInDepthHelp(locale.getArray(DeepHelpLang.MANAGE));
super.setColorScheme(plugin.getColorScheme());
setNodeGroups(
new CommandNode[]{
new ManageRawDataCommand(plugin),
new ManageMoveCommand(plugin),
new ManageBackupCommand(plugin),
new ManageRestoreCommand(plugin),
new ManageRemoveCommand(plugin),
new ManageHotSwapCommand(plugin),
new ManageClearCommand(plugin),
},
new CommandNode[]{
new ManageSetupCommand(plugin),
new ManageConDebugCommand(plugin),
new ManageImportCommand(plugin),
new ManageDisableCommand(plugin)
}
);
CommandNode[] databaseGroup = {
new ManageRawDataCommand(plugin),
new ManageMoveCommand(plugin),
new ManageBackupCommand(plugin),
new ManageRestoreCommand(plugin),
new ManageRemoveCommand(plugin),
new ManageHotSwapCommand(plugin),
new ManageClearCommand(plugin),
};
CommandNode[] pluginGroup = {
new ManageSetupCommand(plugin),
new ManageConDebugCommand(plugin),
new ManageImportCommand(plugin),
new ManageDisableCommand(plugin),
new ManageUninstalledCommand(plugin)
};
setNodeGroups(databaseGroup, pluginGroup);
}
}

View File

@ -88,11 +88,7 @@ public class QInspectCommand extends CommandNode {
sendMessages(sender, container);
} catch (DBOpException e) {
if (e.isFatal()) {
sender.sendMessage("§cFatal database exception occurred: " + e.getMessage());
} else {
sender.sendMessage("§eNon-Fatal database exception occurred: " + e.getMessage());
}
sender.sendMessage("§eDatabase exception occurred: " + e.getMessage());
Log.toLog(this.getClass(), e);
} finally {
this.cancel();

View File

@ -29,14 +29,13 @@ public class WebUserCommand extends TreeCmdNode {
setShortHelp(locale.getString(CmdHelpLang.WEB));
setInDepthHelp(locale.getArray(DeepHelpLang.WEB));
setNodeGroups(
new CommandNode[]{
register,
new WebLevelCommand(plugin),
new WebListUsersCommand(plugin),
new WebCheckCommand(plugin),
new WebDeleteCommand(plugin)
}
);
CommandNode[] webGroup = {
register,
new WebLevelCommand(plugin),
new WebListUsersCommand(plugin),
new WebCheckCommand(plugin),
new WebDeleteCommand(plugin)
};
setNodeGroups(webGroup);
}
}

View File

@ -0,0 +1,96 @@
package com.djrapitops.plan.command.commands.manage;
import com.djrapitops.plan.PlanPlugin;
import com.djrapitops.plan.api.exceptions.database.DBOpException;
import com.djrapitops.plan.system.database.databases.Database;
import com.djrapitops.plan.system.info.connection.ConnectionSystem;
import com.djrapitops.plan.system.info.server.Server;
import com.djrapitops.plan.system.info.server.ServerInfo;
import com.djrapitops.plan.system.locale.Locale;
import com.djrapitops.plan.system.locale.lang.CmdHelpLang;
import com.djrapitops.plan.system.locale.lang.DeepHelpLang;
import com.djrapitops.plan.system.locale.lang.ManageLang;
import com.djrapitops.plan.system.processing.Processing;
import com.djrapitops.plan.system.settings.Permissions;
import com.djrapitops.plugin.api.utility.log.Log;
import com.djrapitops.plugin.command.CommandNode;
import com.djrapitops.plugin.command.CommandType;
import com.djrapitops.plugin.command.ISender;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
/**
* This SubCommand is used to set a server as uninstalled on Plan.
*
* @author Rsl1122
* @since 2.0.0
*/
public class ManageUninstalledCommand extends CommandNode {
private final Locale locale;
public ManageUninstalledCommand(PlanPlugin plugin) {
super("uninstalled", Permissions.MANAGE.getPermission(), CommandType.ALL_WITH_ARGS);
locale = plugin.getSystem().getLocaleSystem().getLocale();
setShortHelp(locale.getString(CmdHelpLang.MANAGE_UNINSTALLED));
setInDepthHelp(locale.getArray(DeepHelpLang.MANAGE_UNINSTALLED));
setArguments("[server/id]");
}
@Override
public void onCommand(ISender sender, String commandLabel, String[] args) {
sender.sendMessage(locale.getString(ManageLang.PROGRESS_START));
Processing.submitNonCritical(() -> {
try {
Optional<Server> serverOptional = getServer(args);
if (!serverOptional.isPresent()) {
sender.sendMessage(locale.getString(ManageLang.PROGRESS_FAIL, locale.getString(ManageLang.NO_SERVER)));
return;
}
Server server = serverOptional.get();
UUID serverUUID = server.getUuid();
if (ServerInfo.getServerUUID().equals(serverUUID)) {
sender.sendMessage(locale.getString(ManageLang.UNINSTALLING_SAME_SERVER));
return;
}
Database.getActive().save().setAsUninstalled(serverUUID);
sender.sendMessage(locale.getString(ManageLang.PROGRESS_SUCCESS));
} catch (DBOpException e) {
sender.sendMessage("§cError occurred: " + e.toString());
Log.toLog(this.getClass(), e);
}
});
}
private Optional<Server> getServer(String[] args) {
if (args.length >= 1 && ConnectionSystem.getInstance().isServerAvailable()) {
Map<UUID, Server> bukkitServers = Database.getActive().fetch().getBukkitServers();
String serverIdentifier = getGivenIdentifier(args);
for (Map.Entry<UUID, Server> entry : bukkitServers.entrySet()) {
Server server = entry.getValue();
if (Integer.toString(server.getId()).equals(serverIdentifier)
|| server.getName().equalsIgnoreCase(serverIdentifier)) {
return Optional.of(server);
}
}
}
return Optional.empty();
}
private String getGivenIdentifier(String[] args) {
StringBuilder idBuilder = new StringBuilder(args[0]);
if (args.length > 1) {
for (int i = 1; i < args.length; i++) {
idBuilder.append(" ").append(args[i]);
}
}
return idBuilder.toString();
}
}

View File

@ -2,9 +2,11 @@ package com.djrapitops.plan.data.container;
import com.djrapitops.plan.data.store.containers.DataContainer;
import com.djrapitops.plan.data.store.keys.SessionKeys;
import com.djrapitops.plan.data.store.mutators.formatting.Formatters;
import com.djrapitops.plan.data.store.objects.DateHolder;
import com.djrapitops.plan.data.time.WorldTimes;
import com.djrapitops.plan.system.info.server.ServerInfo;
import com.djrapitops.plan.system.settings.WorldAliasSettings;
import java.util.*;
@ -55,6 +57,8 @@ public class Session extends DataContainer implements DateHolder {
getValue(SessionKeys.END).orElse(System.currentTimeMillis()) - getUnsafe(SessionKeys.START));
putSupplier(SessionKeys.ACTIVE_TIME, () -> getUnsafe(SessionKeys.LENGTH) - getUnsafe(SessionKeys.AFK_TIME));
putSupplier(SessionKeys.SERVER_UUID, ServerInfo::getServerUUID);
putSupplier(SessionKeys.LONGEST_WORLD_PLAYED, this::getLongestWorldPlayed);
}
/**
@ -96,6 +100,8 @@ public class Session extends DataContainer implements DateHolder {
putSupplier(SessionKeys.LENGTH, () ->
getValue(SessionKeys.END).orElse(System.currentTimeMillis()) - getUnsafe(SessionKeys.START));
putSupplier(SessionKeys.ACTIVE_TIME, () -> getUnsafe(SessionKeys.LENGTH) - getUnsafe(SessionKeys.AFK_TIME));
putSupplier(SessionKeys.LONGEST_WORLD_PLAYED, this::getLongestWorldPlayed);
}
/**
@ -214,4 +220,32 @@ public class Session extends DataContainer implements DateHolder {
private long getAfkTime() {
return afkTime;
}
private String getLongestWorldPlayed() {
Map<String, String> aliases = WorldAliasSettings.getAliases();
if (worldTimes == null) {
return "No World Time Data";
}
if (!supports(SessionKeys.END)) {
return "Current: " + aliases.get(worldTimes.getCurrentWorld());
}
Map<String, Long> playtimePerAlias = worldTimes.getPlaytimePerAlias();
long total = worldTimes.getTotal();
long longest = 0;
String theWorld = "-";
for (Map.Entry<String, Long> entry : playtimePerAlias.entrySet()) {
String world = entry.getKey();
long time = entry.getValue();
if (time > longest) {
longest = time;
theWorld = world;
}
}
double quotient = longest * 1.0 / total;
return theWorld + " (" + Formatters.percentage().apply(quotient) + ")";
}
}

View File

@ -48,25 +48,25 @@ public class InspectContainer {
}
public final String parseHtml() {
StringBuilder html = new StringBuilder();
StringBuilder parsed = new StringBuilder();
if (!values.isEmpty()) {
html.append("<div class=\"body\">");
parsed.append("<div class=\"body\">");
for (Map.Entry<String, String> entry : values.entrySet()) {
html.append("<p>").append(entry.getKey()).append(": ").append(entry.getValue()).append("</p>");
parsed.append("<p>").append(entry.getKey()).append(": ").append(entry.getValue()).append("</p>");
}
html.append("</div>");
parsed.append("</div>");
}
for (Map.Entry<String, String> entry : this.html.entrySet()) {
html.append(entry.getValue());
parsed.append(entry.getValue());
}
for (Map.Entry<String, TableContainer> entry : tables.entrySet()) {
html.append(entry.getValue().parseHtml());
parsed.append(entry.getValue().parseHtml());
}
return html.toString();
return parsed.toString();
}
/**

View File

@ -40,12 +40,10 @@ public class TableContainer {
}
public TableContainer(boolean players, String... header) {
this.header = FormatUtils.mergeArrays(
this(FormatUtils.mergeArrays(
new String[]{Icon.called("user").build() + " Player"},
header
);
this.formatters = new Formatter[this.header.length];
values = new ArrayList<>();
));
}
public final void addRow(Serializable... values) {
@ -60,36 +58,40 @@ public class TableContainer {
}
public final String parseBody() {
StringBuilder body = new StringBuilder();
if (values.isEmpty()) {
addRow("No Data");
}
return Html.TABLE_BODY.parse(buildBody());
}
private String buildBody() {
StringBuilder body = new StringBuilder();
for (Serializable[] row : values) {
int maxIndex = row.length - 1;
body.append("<tr>");
for (int i = 0; i < header.length; i++) {
try {
if (i > maxIndex) {
body.append("<td>-");
} else {
Serializable value = row[i];
Formatter formatter = formatters[i];
body.append("<td").append(formatter != null ? " data-order=\"" + value + "\">" : ">");
body.append(formatter != null ? formatter.apply(value) : value);
}
body.append("</td>");
} catch (ClassCastException | ArrayIndexOutOfBoundsException e) {
throw new IllegalStateException("Invalid formatter given at index " + i + ": " + e.getMessage(), e);
}
}
body.append("</tr>");
appendRow(body, row);
}
return body.toString();
}
return Html.TABLE_BODY.parse(body.toString());
private void appendRow(StringBuilder body, Serializable[] row) {
int maxIndex = row.length - 1;
body.append("<tr>");
for (int i = 0; i < header.length; i++) {
try {
if (i > maxIndex) {
body.append("<td>-");
} else {
Serializable value = row[i];
Formatter formatter = formatters[i];
body.append("<td").append(formatter != null ? " data-order=\"" + value + "\">" : ">");
body.append(formatter != null ? formatter.apply(value) : value);
}
body.append("</td>");
} catch (ClassCastException | ArrayIndexOutOfBoundsException e) {
throw new IllegalStateException("Invalid formatter given at index " + i + ": " + e.getMessage(), e);
}
}
body.append("</tr>");
}
public final void setColor(String color) {
@ -97,12 +99,12 @@ public class TableContainer {
}
public final String parseHeader() {
StringBuilder header = new StringBuilder("<thead" + (color != null ? " class=\"bg-" + color + "\"" : "") + "><tr>");
for (String title : this.header) {
header.append("<th>").append(title).append("</th>");
StringBuilder parsedHeader = new StringBuilder("<thead" + (color != null ? " class=\"bg-" + color + "\"" : "") + "><tr>");
for (String title : header) {
parsedHeader.append("<th>").append(title).append("</th>");
}
header.append("</tr></thead>");
return header.toString();
parsedHeader.append("</tr></thead>");
return parsedHeader.toString();
}
public final void setFormatter(int index, Formatter formatter) {

View File

@ -47,7 +47,7 @@ public class HookHandler implements SubSystem {
@Override
public void disable() {
// Nothing to disable
}
/**

View File

@ -26,7 +26,6 @@ public abstract class PluginData {
private final String sourcePlugin;
private Icon pluginIcon;
private String iconColor;
private String helpText;

View File

@ -22,4 +22,14 @@ public class PlaceholderKey<T> extends Key<T> {
public String getPlaceholder() {
return placeholder;
}
@Override
public boolean equals(Object o) {
return super.equals(o);
}
@Override
public int hashCode() {
return super.hashCode();
}
}

View File

@ -201,14 +201,12 @@ public class AnalysisContainer extends DataContainer {
putSupplier(AnalysisKeys.UNIQUE_PLAYERS_PER_DAY, () -> getUnsafe(AnalysisKeys.SESSIONS_MUTATOR).uniqueJoinsPerDay());
putSupplier(AnalysisKeys.NEW_PLAYERS_PER_DAY, () -> getUnsafe(AnalysisKeys.PLAYERS_MUTATOR).newPerDay());
putSupplier(AnalysisKeys.UNIQUE_PLAYERS_SERIES, () ->
new AbstractLineGraph(MutatorFunctions.toPoints(
getUnsafe(AnalysisKeys.UNIQUE_PLAYERS_PER_DAY))
putSupplier(AnalysisKeys.UNIQUE_PLAYERS_SERIES, () -> new AbstractLineGraph(
MutatorFunctions.toPoints(getUnsafe(AnalysisKeys.UNIQUE_PLAYERS_PER_DAY))
).toHighChartsSeries()
);
putSupplier(AnalysisKeys.NEW_PLAYERS_SERIES, () ->
new AbstractLineGraph(MutatorFunctions.toPoints(
getUnsafe(AnalysisKeys.NEW_PLAYERS_PER_DAY))
putSupplier(AnalysisKeys.NEW_PLAYERS_SERIES, () -> new AbstractLineGraph(
MutatorFunctions.toPoints(getUnsafe(AnalysisKeys.NEW_PLAYERS_PER_DAY))
).toHighChartsSeries()
);

View File

@ -23,12 +23,7 @@ public class PlayerContainer extends DataContainer {
}
public ActivityIndex getActivityIndex(long date) {
ActivityIndex index = activityIndexCache.get(date);
if (index == null) {
index = new ActivityIndex(this, date);
activityIndexCache.put(date, index);
}
return index;
return activityIndexCache.computeIfAbsent(date, time -> new ActivityIndex(this, time));
}
public boolean playedBetween(long after, long before) {

View File

@ -32,6 +32,8 @@ public class SessionKeys {
public static final Key<Integer> DEATH_COUNT = CommonKeys.DEATH_COUNT;
public static final Key<List<PlayerDeath>> PLAYER_DEATHS = CommonKeys.PLAYER_DEATHS;
public static final Key<String> LONGEST_WORLD_PLAYED = new Key<>(String.class, "longest_world_played");
private SessionKeys() {
/* Static variable class */
}

View File

@ -5,6 +5,7 @@ import com.djrapitops.plugin.api.TimeAmount;
import java.util.ArrayList;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;
public class DateHoldersMutator<T extends DateHolder> {
@ -15,11 +16,11 @@ public class DateHoldersMutator<T extends DateHolder> {
this.dateHolders = dateHolders;
}
public TreeMap<Long, List<T>> groupByStartOfMinute() {
public SortedMap<Long, List<T>> groupByStartOfMinute() {
return groupByStartOfSections(TimeAmount.MINUTE.ms());
}
private TreeMap<Long, List<T>> groupByStartOfSections(long sectionLength) {
private SortedMap<Long, List<T>> groupByStartOfSections(long sectionLength) {
TreeMap<Long, List<T>> map = new TreeMap<>();
if (dateHolders.isEmpty()) {
@ -37,9 +38,9 @@ public class DateHoldersMutator<T extends DateHolder> {
return map;
}
public TreeMap<Long, List<T>> groupByStartOfDay() {
public SortedMap<Long, List<T>> groupByStartOfDay() {
long twentyFourHours = 24L * TimeAmount.HOUR.ms();
TreeMap<Long, List<T>> map = groupByStartOfSections(twentyFourHours);
SortedMap<Long, List<T>> map = groupByStartOfSections(twentyFourHours);
// Empty map firstKey attempt causes NPE if not checked.
if (!map.isEmpty()) {

View File

@ -21,4 +21,8 @@ public class MutatorFunctions {
.average().orElse(0);
}
private MutatorFunctions() {
// Static method class.
}
}

View File

@ -6,7 +6,7 @@ import com.djrapitops.plan.data.store.keys.CommonKeys;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeMap;
import java.util.SortedMap;
import java.util.UUID;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@ -33,7 +33,7 @@ public class PingMutator {
public PingMutator mutateToByMinutePings() {
DateHoldersMutator<Ping> dateMutator = new DateHoldersMutator<>(pings);
TreeMap<Long, List<Ping>> byStartOfMinute = dateMutator.groupByStartOfMinute();
SortedMap<Long, List<Ping>> byStartOfMinute = dateMutator.groupByStartOfMinute();
return new PingMutator(byStartOfMinute.entrySet().stream()
.map(entry -> {

View File

@ -9,7 +9,6 @@ import com.djrapitops.plan.data.store.keys.PlayerKeys;
import com.djrapitops.plan.data.store.keys.ServerKeys;
import com.djrapitops.plan.data.store.keys.SessionKeys;
import com.djrapitops.plan.data.store.objects.DateObj;
import com.djrapitops.plan.utilities.analysis.AnalysisUtils;
import com.djrapitops.plugin.api.TimeAmount;
import java.util.*;
@ -158,7 +157,7 @@ public class PlayersMutator {
List<DateObj> registerDates = registerDates().stream()
.map(value -> new DateObj<>(value, value))
.collect(Collectors.toList());
TreeMap<Long, List<DateObj>> byDay = new DateHoldersMutator<>(registerDates).groupByStartOfDay();
SortedMap<Long, List<DateObj>> byDay = new DateHoldersMutator<>(registerDates).groupByStartOfDay();
TreeMap<Long, Integer> byDayCounts = new TreeMap<>();
for (Map.Entry<Long, List<DateObj>> entry : byDay.entrySet()) {
@ -210,8 +209,8 @@ public class PlayersMutator {
.map(player -> new RetentionData(player, onlineResolver))
.collect(Collectors.toList());
RetentionData avgRetained = AnalysisUtils.average(retained);
RetentionData avgNotRetained = AnalysisUtils.average(notRetained);
RetentionData avgRetained = RetentionData.average(retained);
RetentionData avgNotRetained = RetentionData.average(notRetained);
List<PlayerContainer> toBeRetained = new ArrayList<>();
for (PlayerContainer player : compareTo) {

View File

@ -9,6 +9,7 @@ import com.djrapitops.plan.data.store.keys.PlayerKeys;
import com.djrapitops.plugin.api.TimeAmount;
import com.google.common.base.Objects;
import java.util.Collection;
import java.util.Optional;
/**
@ -22,6 +23,23 @@ public class RetentionData {
private final double activityIndex;
private double onlineOnJoin;
public static RetentionData average(Collection<RetentionData> stuck) {
int size = stuck.size();
double totalIndex = 0.0;
double totalPlayersOnline = 0.0;
for (RetentionData retentionData : stuck) {
totalIndex += retentionData.getActivityIndex();
totalPlayersOnline += retentionData.getOnlineOnJoin();
}
double averageIndex = totalIndex / (double) size;
double averagePlayersOnline = totalPlayersOnline / (double) size;
return new RetentionData(averageIndex, averagePlayersOnline);
}
public RetentionData(double activityIndex, double onlineOnJoin) {
this.activityIndex = activityIndex;
this.onlineOnJoin = onlineOnJoin;

View File

@ -156,7 +156,7 @@ public class SessionsMutator {
}
public TreeMap<Long, Integer> uniqueJoinsPerDay() {
TreeMap<Long, List<Session>> byStartOfDay = toDateHoldersMutator().groupByStartOfDay();
SortedMap<Long, List<Session>> byStartOfDay = toDateHoldersMutator().groupByStartOfDay();
TreeMap<Long, Integer> uniqueJoins = new TreeMap<>();
for (Map.Entry<Long, List<Session>> entry : byStartOfDay.entrySet()) {

View File

@ -11,13 +11,13 @@ import org.apache.commons.lang3.StringUtils;
public class TimeAmountFormatter implements Formatter<Long> {
// Placeholders for the config settings
private final String zeroPH = "%zero%";
private final String secondsPH = "%seconds%";
private final String minutesPH = "%minutes%";
private final String hoursPH = "%hours%";
private final String daysPH = "%days%";
private final String monthsPH = "%months%";
private final String yearsPH = "%years%";
private static final String ZERO_PH = "%zero%";
private static final String SECONDS_PH = "%seconds%";
private static final String MINUTES_PH = "%minutes%";
private static final String HOURS_PH = "%hours%";
private static final String DAYS_PH = "%days%";
private static final String MONTHS_PH = "%months%";
private static final String YEARS_PH = "%years%";
@Override
public String apply(Long ms) {
@ -50,7 +50,7 @@ public class TimeAmountFormatter implements Formatter<Long> {
appendMinutes(builder, minutes, hours, hourFormat, minuteFormat);
appendSeconds(builder, seconds, minutes, hours, hourFormat, minuteFormat, secondFormat);
String formattedTime = StringUtils.remove(builder.toString(), zeroPH);
String formattedTime = StringUtils.remove(builder.toString(), ZERO_PH);
if (formattedTime.isEmpty()) {
return Settings.FORMAT_ZERO_SECONDS.toString();
}
@ -59,15 +59,15 @@ public class TimeAmountFormatter implements Formatter<Long> {
private void appendSeconds(StringBuilder builder, long seconds, long minutes, long hours, String fHours, String fMinutes, String fSeconds) {
if (seconds != 0) {
String s = fSeconds.replace(secondsPH, String.valueOf(seconds));
if (minutes == 0 && s.contains(minutesPH)) {
if (hours == 0 && fMinutes.contains(hoursPH)) {
builder.append(fHours.replace(zeroPH, "0").replace(hoursPH, "0"));
String s = fSeconds.replace(SECONDS_PH, String.valueOf(seconds));
if (minutes == 0 && s.contains(MINUTES_PH)) {
if (hours == 0 && fMinutes.contains(HOURS_PH)) {
builder.append(fHours.replace(ZERO_PH, "0").replace(HOURS_PH, "0"));
}
builder.append(fMinutes.replace(hoursPH, "").replace(zeroPH, "0").replace(minutesPH, "0"));
builder.append(fMinutes.replace(HOURS_PH, "").replace(ZERO_PH, "0").replace(MINUTES_PH, "0"));
}
s = s.replace(minutesPH, "");
if (s.contains(zeroPH) && String.valueOf(seconds).length() == 1) {
s = s.replace(MINUTES_PH, "");
if (s.contains(ZERO_PH) && String.valueOf(seconds).length() == 1) {
builder.append('0');
}
builder.append(s);
@ -76,13 +76,13 @@ public class TimeAmountFormatter implements Formatter<Long> {
private void appendMinutes(StringBuilder builder, long minutes, long hours, String fHours, String fMinutes) {
if (minutes != 0) {
String m = fMinutes.replace(minutesPH, String.valueOf(minutes));
if (hours == 0 && m.contains(hoursPH)) {
builder.append(fHours.replace(zeroPH, "0").replace(hoursPH, "0"));
m = m.replace(hoursPH, "");
String m = fMinutes.replace(MINUTES_PH, String.valueOf(minutes));
if (hours == 0 && m.contains(HOURS_PH)) {
builder.append(fHours.replace(ZERO_PH, "0").replace(HOURS_PH, "0"));
m = m.replace(HOURS_PH, "");
}
m = m.replace(hoursPH, "");
if (m.contains(zeroPH) && String.valueOf(minutes).length() == 1) {
m = m.replace(HOURS_PH, "");
if (m.contains(ZERO_PH) && String.valueOf(minutes).length() == 1) {
builder.append('0');
}
builder.append(m);
@ -91,8 +91,8 @@ public class TimeAmountFormatter implements Formatter<Long> {
private void appendHours(StringBuilder builder, long hours, String fHours) {
if (hours != 0) {
String h = fHours.replace(hoursPH, String.valueOf(hours));
if (h.contains(zeroPH) && String.valueOf(hours).length() == 1) {
String h = fHours.replace(HOURS_PH, String.valueOf(hours));
if (h.contains(ZERO_PH) && String.valueOf(hours).length() == 1) {
builder.append('0');
}
builder.append(h);
@ -102,21 +102,21 @@ public class TimeAmountFormatter implements Formatter<Long> {
private void appendDays(StringBuilder builder, long days) {
String singular = Settings.FORMAT_DAY.toString();
String plural = Settings.FORMAT_DAYS.toString();
appendValue(builder, days, singular, plural, daysPH);
appendValue(builder, days, singular, plural, DAYS_PH);
}
private void appendMonths(StringBuilder builder, long months) {
String singular = Settings.FORMAT_MONTH.toString();
String plural = Settings.FORMAT_MONTHS.toString();
appendValue(builder, months, singular, plural, monthsPH);
appendValue(builder, months, singular, plural, MONTHS_PH);
}
private void appendYears(StringBuilder builder, long years) {
String singular = Settings.FORMAT_YEAR.toString();
String plural = Settings.FORMAT_YEARS.toString();
appendValue(builder, years, singular, plural, yearsPH);
appendValue(builder, years, singular, plural, YEARS_PH);
}
private void appendValue(StringBuilder builder, long amount, String singular, String plural, String replace) {

View File

@ -63,7 +63,7 @@ public abstract class AbstractHealthInfo {
regularRemainCompareSet.removeAll(veryActiveNow);
int notRegularAnymore = regularRemainCompareSet.size();
int remain = activeFWAGNum - notRegularAnymore;
double percRemain = remain * 100.0 / activeFWAGNum;
double percRemain = activeFWAGNum != 0 ? remain * 100.0 / activeFWAGNum : 100.0;
int newActive = getNewActive(veryActiveNow, activeNow, regularNow, veryActiveFWAG, activeFWAG, regularFWAG);

View File

@ -38,6 +38,7 @@ public class HealthInformation extends AbstractHealthInfo {
calculate();
}
@Override
public String toHtml() {
StringBuilder healthNoteBuilder = new StringBuilder();
for (String healthNote : notes) {

View File

@ -2,7 +2,6 @@ package com.djrapitops.plan.data.time;
import com.djrapitops.plugin.utilities.Verify;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
@ -12,7 +11,7 @@ import java.util.Objects;
*
* @author Rsl1122
*/
public abstract class TimeKeeper implements Serializable {
public abstract class TimeKeeper {
protected Map<String, Long> times;
protected String state;

View File

@ -1,9 +1,11 @@
package com.djrapitops.plan.data.time;
import java.io.Serializable;
import com.djrapitops.plan.system.settings.WorldAliasSettings;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* Class that tracks the time spent in each World based on GMTimes.
@ -11,9 +13,9 @@ import java.util.Objects;
* @author Rsl1122
* @since 4.0.0
*/
public class WorldTimes implements Serializable {
public class WorldTimes {
private final Map<String, GMTimes> worldTimes;
private final Map<String, GMTimes> times;
private String currentWorld;
private String currentGamemode;
@ -25,7 +27,7 @@ public class WorldTimes implements Serializable {
* @param time Epoch ms the time calculation should start
*/
public WorldTimes(String startingWorld, String startingGM, long time) {
worldTimes = new HashMap<>();
times = new HashMap<>();
currentWorld = startingWorld;
currentGamemode = startingGM;
addWorld(startingWorld, startingGM, time);
@ -37,11 +39,11 @@ public class WorldTimes implements Serializable {
* @param times Map of each World's GMTimes object.
*/
public WorldTimes(Map<String, GMTimes> times) {
worldTimes = times;
this.times = times;
}
private void addWorld(String worldName, String gameMode, long changeTime) {
worldTimes.put(worldName, new GMTimes(gameMode, changeTime));
times.put(worldName, new GMTimes(gameMode, changeTime));
}
/**
@ -62,18 +64,18 @@ public class WorldTimes implements Serializable {
* @param changeTime Epoch ms the change occurred.
*/
public void updateState(String worldName, String gameMode, long changeTime) {
GMTimes currentGMTimes = worldTimes.get(currentWorld);
GMTimes currentGMTimes = times.get(currentWorld);
if (worldName.equals(currentWorld)) {
currentGMTimes.changeState(gameMode, changeTime);
} else {
GMTimes newGMTimes = worldTimes.get(worldName);
GMTimes newGMTimes = times.get(worldName);
if (newGMTimes == null) {
addWorld(worldName, gameMode, currentGMTimes.getLastStateChange());
}
currentGMTimes.changeState(currentGamemode, changeTime);
}
for (GMTimes gmTimes : worldTimes.values()) {
for (GMTimes gmTimes : times.values()) {
gmTimes.setLastStateChange(changeTime);
}
@ -88,12 +90,12 @@ public class WorldTimes implements Serializable {
* @return total milliseconds spent in a world.
*/
public long getWorldPlaytime(String world) {
GMTimes gmTimes = worldTimes.get(world);
GMTimes gmTimes = times.get(world);
return gmTimes != null ? gmTimes.getTotal() : 0;
}
public long getTotal() {
return worldTimes.values().stream()
return times.values().stream()
.mapToLong(GMTimes::getTotal)
.sum();
}
@ -109,20 +111,15 @@ public class WorldTimes implements Serializable {
* @return GMTimes object with play times of each GameMode.
*/
public GMTimes getGMTimes(String world) {
return worldTimes.getOrDefault(world, new GMTimes());
return times.getOrDefault(world, new GMTimes());
}
/**
* Used to get the Map for saving.
*
* @return Current time map.
*/
public Map<String, GMTimes> getWorldTimes() {
return worldTimes;
return times;
}
public void setGMTimesForWorld(String world, GMTimes gmTimes) {
worldTimes.put(world, gmTimes);
times.put(world, gmTimes);
}
@Override
@ -130,21 +127,21 @@ public class WorldTimes implements Serializable {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
WorldTimes that = (WorldTimes) o;
return Objects.equals(worldTimes, that.worldTimes) &&
return Objects.equals(times, that.times) &&
Objects.equals(currentWorld, that.currentWorld) &&
Objects.equals(currentGamemode, that.currentGamemode);
}
@Override
public int hashCode() {
return Objects.hash(worldTimes, currentWorld, currentGamemode);
return Objects.hash(times, currentWorld, currentGamemode);
}
@Override
public String toString() {
StringBuilder b = new StringBuilder("WorldTimes (Current: " + currentWorld + "){\n");
for (Map.Entry<String, GMTimes> entry : worldTimes.entrySet()) {
for (Map.Entry<String, GMTimes> entry : times.entrySet()) {
GMTimes value = entry.getValue();
b.append("World '").append(entry.getKey()).append("':\n")
.append(" Total: ").append(value.getTotal()).append("\n")
@ -160,8 +157,7 @@ public class WorldTimes implements Serializable {
}
public void add(WorldTimes toAdd) {
Map<String, GMTimes> times = toAdd.getWorldTimes();
for (Map.Entry<String, GMTimes> entry : times.entrySet()) {
for (Map.Entry<String, GMTimes> entry : toAdd.getWorldTimes().entrySet()) {
String worldName = entry.getKey();
GMTimes gmTimes = entry.getValue();
@ -169,7 +165,34 @@ public class WorldTimes implements Serializable {
for (String gm : GMTimes.getGMKeyArray()) {
currentGMTimes.addTime(gm, gmTimes.getTime(gm));
}
worldTimes.put(worldName, currentGMTimes);
this.times.put(worldName, currentGMTimes);
}
}
public Map<String, Long> getPlaytimePerAlias() {
Map<String, Long> playtimePerWorld = getWorldTimes() // WorldTimes Map<String, GMTimes>
.entrySet().stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
entry -> entry.getValue().getTotal() // GMTimes.getTotal
));
Map<String, String> aliases = WorldAliasSettings.getAliases();
Map<String, Long> playtimePerAlias = new HashMap<>();
for (Map.Entry<String, Long> entry : playtimePerWorld.entrySet()) {
String worldName = entry.getKey();
long playtime = entry.getValue();
if (!aliases.containsKey(worldName)) {
aliases.put(worldName, worldName);
WorldAliasSettings.addWorld(worldName);
}
String alias = aliases.get(worldName);
playtimePerAlias.put(alias, playtimePerAlias.getOrDefault(alias, 0L) + playtime);
}
return playtimePerAlias;
}
}

View File

@ -44,6 +44,9 @@ public class DataCache extends SessionCache implements SubSystem {
@Override
public void disable() {
playerNames.clear();
uuids.clear();
displayNames.clear();
}
public static DataCache getInstance() {

View File

@ -3,7 +3,6 @@ package com.djrapitops.plan.system.cache;
import com.djrapitops.plan.data.store.Key;
import com.djrapitops.plan.data.store.containers.AnalysisContainer;
import com.djrapitops.plan.data.store.containers.DataContainer;
import com.djrapitops.plan.data.store.containers.NetworkContainer;
import com.djrapitops.plan.data.store.containers.PlayerContainer;
import com.djrapitops.plan.system.database.databases.Database;
import com.djrapitops.plugin.api.TimeAmount;
@ -20,8 +19,6 @@ public class DataContainerCache extends DataContainer {
public DataContainerCache() {
super(TimeAmount.SECOND.ms() * 10L);
putSupplier(Keys.NETWORK_CONTAINER, Suppliers.NETWORK_CONTAINER);
}
public PlayerContainer getPlayerContainer(UUID uuid) {
@ -32,20 +29,14 @@ public class DataContainerCache extends DataContainer {
return getAndCacheSupplier(Keys.analysisContainer(serverUUID), Suppliers.analysisContainer(serverUUID));
}
public <T> T getAndCacheSupplier(Key<T> key, Supplier<T> ifNotPresent) {
private <T> T getAndCacheSupplier(Key<T> key, Supplier<T> ifNotPresent) {
if (!supports(key)) {
putSupplier(key, ifNotPresent);
}
return getUnsafe(key);
}
public NetworkContainer getNetworkContainer() {
return getAndCacheSupplier(Keys.NETWORK_CONTAINER, Suppliers.NETWORK_CONTAINER);
}
public static class Keys {
static final Key<NetworkContainer> NETWORK_CONTAINER = new Key<>(NetworkContainer.class, "NETWORK_CONTAINER");
private static class Keys {
static Key<AnalysisContainer> analysisContainer(UUID serverUUID) {
return new Key<>(AnalysisContainer.class, "ANALYSIS_CONTAINER:" + serverUUID);
}
@ -54,11 +45,12 @@ public class DataContainerCache extends DataContainer {
return new Key<>(PlayerContainer.class, "PLAYER_CONTAINER:" + uuid);
}
private Keys() {
// Static utility class
}
}
public static class Suppliers {
static final Supplier<NetworkContainer> NETWORK_CONTAINER = () -> Database.getActive().fetch().getNetworkContainer();
private static class Suppliers {
static Supplier<AnalysisContainer> analysisContainer(UUID serverUUID) {
return () -> new AnalysisContainer(Database.getActive().fetch().getServerContainer(serverUUID));
}
@ -66,6 +58,10 @@ public class DataContainerCache extends DataContainer {
static Supplier<PlayerContainer> playerContainer(UUID uuid) {
return () -> Database.getActive().fetch().getPlayerContainer(uuid);
}
private Suppliers() {
// Static utility class
}
}
}

View File

@ -37,12 +37,12 @@ import java.util.zip.GZIPInputStream;
public class GeolocationCache implements SubSystem {
private final Supplier<Locale> locale;
private final Map<String, String> geolocationCache;
private final Map<String, String> cached;
private File geolocationDB;
public GeolocationCache(Supplier<Locale> locale) {
this.locale = locale;
geolocationCache = new HashMap<>();
cached = new HashMap<>();
}
@Override
@ -61,20 +61,10 @@ public class GeolocationCache implements SubSystem {
}
}
@Override
public void disable() {
}
private static GeolocationCache getInstance() {
GeolocationCache geolocationCache = CacheSystem.getInstance().getGeolocationCache();
Verify.nullCheck(geolocationCache, () -> new IllegalStateException("GeolocationCache was not initialized."));
return geolocationCache;
}
/**
* Retrieves the country in full length (e.g. United States) from the IP Address.
* <p>
* This method uses the {@code geolocationCache}, every first access is getting cached and then retrieved later.
* This method uses {@code cached}, every first access is getting cached and then retrieved later.
*
* @param ipAddress The IP Address from which the country is retrieved
* @return The name of the country in full length.
@ -90,12 +80,28 @@ public class GeolocationCache implements SubSystem {
return country;
} else {
country = getUnCachedCountry(ipAddress);
getInstance().geolocationCache.put(ipAddress, country);
getInstance().cached.put(ipAddress, country);
return country;
}
}
private static GeolocationCache getInstance() {
GeolocationCache geolocationCache = CacheSystem.getInstance().getGeolocationCache();
Verify.nullCheck(geolocationCache, () -> new IllegalStateException("GeolocationCache was not initialized."));
return geolocationCache;
}
/**
* Returns the cached country
*
* @param ipAddress The IP Address which is retrieved out of the cache
* @return The cached country, {@code null} if the country is not cached
*/
private static String getCachedCountry(String ipAddress) {
return getInstance().cached.get(ipAddress);
}
/**
* Retrieves the country in full length (e.g. United States) from the IP Address.
* <p>
@ -147,16 +153,6 @@ public class GeolocationCache implements SubSystem {
}
}
/**
* Returns the cached country
*
* @param ipAddress The IP Address which is retrieved out of the cache
* @return The cached country, {@code null} if the country is not cached
*/
private static String getCachedCountry(String ipAddress) {
return getInstance().geolocationCache.get(ipAddress);
}
/**
* Checks if the IP Address is cached
*
@ -164,13 +160,18 @@ public class GeolocationCache implements SubSystem {
* @return true if the IP Address is cached
*/
public static boolean isCached(String ipAddress) {
return getInstance().geolocationCache.containsKey(ipAddress);
return getInstance().cached.containsKey(ipAddress);
}
@Override
public void disable() {
cached.clear();
}
/**
* Clears the cache
*/
public void clearCache() {
geolocationCache.clear();
cached.clear();
}
}

View File

@ -69,4 +69,6 @@ public interface SaveOperations {
void webUser(WebUser webUser);
void ping(UUID uuid, Ping ping);
void setAsUninstalled(UUID serverUUID);
}

View File

@ -135,4 +135,9 @@ public class SQLSaveOps extends SQLOps implements SaveOperations {
public void ping(UUID uuid, Ping ping) {
pingTable.insertPing(uuid, ping);
}
@Override
public void setAsUninstalled(UUID serverUUID) {
serverTable.setAsUninstalled(serverUUID);
}
}

View File

@ -55,7 +55,7 @@ public class ServerTable extends Table {
.column(Col.SERVER_UUID, Sql.varchar(36)).notNull().unique()
.column(Col.NAME, Sql.varchar(100))
.column(Col.WEBSERVER_ADDRESS, Sql.varchar(100))
.column(Col.INSTALLED, Sql.BOOL).notNull().defaultValue(false)
.column(Col.INSTALLED, Sql.BOOL).notNull().defaultValue(true)
.column(Col.MAX_PLAYERS, Sql.INT).notNull().defaultValue("-1")
.primaryKey(usingMySQL, Col.SERVER_ID)
.toString()
@ -246,12 +246,14 @@ public class ServerTable extends Table {
public Map<UUID, Server> getBukkitServers() {
String sql = Select.from(tableName, "*")
.where(Col.NAME + "!=?")
.and(Col.INSTALLED + "=?")
.toString();
return query(new QueryStatement<Map<UUID, Server>>(sql, 100) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, "BungeeCord");
statement.setBoolean(2, true);
}
@Override
@ -364,6 +366,18 @@ public class ServerTable extends Table {
});
}
public void setAsUninstalled(UUID serverUUID) {
String sql = "UPDATE " + tableName + " SET (" + Col.INSTALLED + "=?) WHERE " + Col.SERVER_UUID + "=?";
execute(new ExecStatement(sql) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setBoolean(1, false);
statement.setString(2, serverUUID.toString());
}
});
}
public enum Col implements Column {
SERVER_ID("id"),
SERVER_UUID("uuid"),

View File

@ -178,5 +178,20 @@ public class WorldTable extends Table {
return column;
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof WorldTable)) return false;
if (!super.equals(o)) return false;
WorldTable that = (WorldTable) o;
return Objects.equals(statementSelectID, that.statementSelectID) &&
Objects.equals(serverTable, that.serverTable);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), statementSelectID, serverTable);
}
}

View File

@ -286,8 +286,8 @@ public class WorldTimesTable extends UserIDTable {
public void addWorldTimesToSessions(Map<UUID, Map<UUID, List<Session>>> map) {
Map<Integer, WorldTimes> worldTimesBySessionID = getAllWorldTimesBySessionID();
for (UUID serverUUID : map.keySet()) {
for (List<Session> sessions : map.get(serverUUID).values()) {
for (Map.Entry<UUID, Map<UUID, List<Session>>> entry : map.entrySet()) {
for (List<Session> sessions : entry.getValue().values()) {
for (Session session : sessions) {
WorldTimes worldTimes = worldTimesBySessionID.get(session.getUnsafe(SessionKeys.DB_ID));
if (worldTimes != null) {
@ -377,4 +377,21 @@ public class WorldTimesTable extends UserIDTable {
return column;
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof WorldTimesTable)) return false;
if (!super.equals(o)) return false;
WorldTimesTable that = (WorldTimesTable) o;
return Objects.equals(serverTable, that.serverTable) &&
Objects.equals(worldTable, that.worldTable) &&
Objects.equals(sessionsTable, that.sessionsTable) &&
Objects.equals(insertStatement, that.insertStatement);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), serverTable, worldTable, sessionsTable, insertStatement);
}
}

View File

@ -77,6 +77,6 @@ public class FileSystem implements SubSystem {
@Override
public void disable() {
// No disable actions necessary.
}
}

View File

@ -7,18 +7,15 @@ package com.djrapitops.plan.system.info;
import com.djrapitops.plan.api.exceptions.ParseException;
import com.djrapitops.plan.api.exceptions.connection.NoServersException;
import com.djrapitops.plan.api.exceptions.connection.WebException;
import com.djrapitops.plan.api.exceptions.connection.WebFailException;
import com.djrapitops.plan.data.store.containers.NetworkContainer;
import com.djrapitops.plan.system.cache.CacheSystem;
import com.djrapitops.plan.system.info.connection.BungeeConnectionSystem;
import com.djrapitops.plan.system.info.request.CacheRequest;
import com.djrapitops.plan.system.info.request.GenerateInspectPageRequest;
import com.djrapitops.plan.system.info.request.InfoRequest;
import com.djrapitops.plan.system.info.server.ServerInfo;
import com.djrapitops.plan.system.webserver.pages.parsing.NetworkPage;
import com.djrapitops.plan.system.webserver.response.cache.PageId;
import com.djrapitops.plan.system.webserver.response.cache.ResponseCache;
import com.djrapitops.plan.system.webserver.response.pages.AnalysisPageResponse;
import com.djrapitops.plan.system.webserver.cache.PageId;
import com.djrapitops.plan.system.webserver.cache.ResponseCache;
import com.djrapitops.plan.system.webserver.response.errors.InternalErrorResponse;
import com.djrapitops.plan.system.webserver.response.pages.NetworkPageResponse;
/**
* InfoSystem for Bungee.
@ -43,13 +40,13 @@ public class BungeeInfoSystem extends InfoSystem {
}
@Override
public void updateNetworkPage() throws WebException {
try {
NetworkContainer networkContainer = CacheSystem.getInstance().getDataContainerCache().getNetworkContainer();
String html = new NetworkPage(networkContainer).toHtml();
ResponseCache.cacheResponse(PageId.SERVER.of(ServerInfo.getServerUUID()), () -> new AnalysisPageResponse(html));
} catch (ParseException e) {
throw new WebFailException("Exception during Network Page Parsing", e);
}
public void updateNetworkPage() {
ResponseCache.cacheResponse(PageId.SERVER.of(ServerInfo.getServerUUID()), () -> {
try {
return new NetworkPageResponse();
} catch (ParseException e) {
return new InternalErrorResponse("Network page parsing failed.", e);
}
});
}
}

View File

@ -156,7 +156,6 @@ public abstract class InfoSystem implements SubSystem {
Server bungee = new Server(-1, null, "Bungee", addressToRequestServer, -1);
String addressOfThisServer = WebServerSystem.getInstance().getWebServer().getAccessAddress();
ConnectionSystem connectionSystem = ConnectionSystem.getInstance();
connectionSystem.setSetupAllowed(true);
connectionSystem.sendInfoRequest(new SendDBSettingsRequest(addressOfThisServer), bungee);
}

View File

@ -14,9 +14,7 @@ import com.djrapitops.plan.system.webserver.WebServerSystem;
import com.djrapitops.plugin.api.TimeAmount;
import com.djrapitops.plugin.api.utility.log.Log;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
/**
* ConnectionSystem for Bungee.
@ -59,20 +57,6 @@ public class BungeeConnectionSystem extends ConnectionSystem {
return server;
}
private Server getOneBukkitServer() {
int rand = ThreadLocalRandom.current().nextInt(bukkitServers.size());
int i = 0;
for (Server server : bukkitServers.values()) {
if (i == rand) {
return server;
}
i++;
}
// Fallback if code above fails (Shouldn't)
Optional<Server> first = bukkitServers.values().stream().findAny();
return first.orElse(null);
}
@Override
public void sendWideInfoRequest(WideRequest infoRequest) throws NoServersException {
refreshServerMap();
@ -99,8 +83,4 @@ public class BungeeConnectionSystem extends ConnectionSystem {
refreshServerMap();
}
@Override
public void disable() {
}
}

View File

@ -68,9 +68,9 @@ public class ConnectionIn {
private Map<String, String> readVariables(Request request) throws WebException {
String requestBody = readRequestBody(request.getRequestBody());
String[] variables = requestBody.split(";&variable;");
String[] bodyVariables = requestBody.split(";&variable;");
return Arrays.stream(variables)
return Arrays.stream(bodyVariables)
.map(variable -> variable.split("=", 2))
.filter(splitVariables -> splitVariables.length == 2)
.collect(Collectors.toMap(splitVariables -> splitVariables[0], splitVariables -> splitVariables[1], (a, b) -> b));

View File

@ -11,6 +11,7 @@ import com.djrapitops.plugin.api.utility.log.Log;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* Class responsible for logging what ConnectionOut objects get in return.
@ -90,6 +91,20 @@ public class ConnectionLog {
public int compareTo(Entry o) {
return Long.compare(o.date, this.date);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Entry)) return false;
Entry entry = (Entry) o;
return responseCode == entry.responseCode &&
date == entry.date;
}
@Override
public int hashCode() {
return Objects.hash(responseCode, date);
}
}
}

View File

@ -32,6 +32,8 @@ import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.Properties;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Represents an outbound action request to another Plan server.
@ -51,7 +53,7 @@ public class ConnectionOut {
properties.setProperty("sun.net.client.defaultReadTimeout", Long.toString(TimeAmount.MINUTE.ms()));
properties.setProperty("sun.net.http.retryPost", Boolean.toString(false));
} catch (Exception e) {
e.printStackTrace();
Logger.getGlobal().log(Level.WARNING, "[Plan] Failed to set sun client timeout system properties.", e);
}
}
@ -90,7 +92,7 @@ public class ConnectionOut {
handleResult(url, parameters, responseCode);
} catch (SocketTimeoutException e) {
ConnectionLog.logConnectionTo(toServer, infoRequest, 0);
throw new ConnectionFailException("Connection timed out after 10 seconds.", e);
throw new ConnectionFailException("Connection to " + address + " timed out after 10 seconds.", e);
} catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException | IOException e) {
if (Settings.DEV_MODE.isTrue()) {
Log.warn("THIS ERROR IS ONLY LOGGED IN DEV MODE:");

View File

@ -111,4 +111,11 @@ public abstract class ConnectionSystem implements SubSystem {
public List<Server> getBukkitServers() {
return new ArrayList<>(bukkitServers.values());
}
@Override
public void disable() {
setupAllowed = false;
bukkitServers.clear();
dataRequests.clear();
}
}

View File

@ -11,7 +11,7 @@ import com.djrapitops.plan.system.locale.lang.ErrorPageLang;
import com.djrapitops.plan.system.webserver.Request;
import com.djrapitops.plan.system.webserver.pages.PageHandler;
import com.djrapitops.plan.system.webserver.response.Response;
import com.djrapitops.plan.system.webserver.response.api.BadRequestResponse;
import com.djrapitops.plan.system.webserver.response.errors.BadRequestResponse;
import com.djrapitops.plan.system.webserver.response.errors.NotFoundResponse;
import com.djrapitops.plugin.utilities.Verify;

View File

@ -116,9 +116,4 @@ public class ServerConnectionSystem extends ConnectionSystem {
Log.info(locale.get().getString(PluginLang.ENABLE_NOTIFY_ADDRESS_CONFIRMATION, webServerAddress));
}
}
@Override
public void disable() {
}
}

View File

@ -25,11 +25,11 @@ public class WebExceptionLogger {
function.apply();
} catch (ConnectionFailException e) {
if (shouldLog(e)) {
Log.warn(e.getMessage());
Log.debug(e.getMessage());
}
} catch (UnsupportedTransferDatabaseException | UnauthorizedServerException
| NotFoundException | NoServersException e) {
Log.warn(e.getMessage());
Log.debug(e.getMessage());
} catch (WebException e) {
Log.toLog(c, e);
}
@ -63,4 +63,7 @@ public class WebExceptionLogger {
return null;
}
private WebExceptionLogger() {
// Static method class.
}
}

View File

@ -8,10 +8,10 @@ import com.djrapitops.plan.api.exceptions.connection.BadRequestException;
import com.djrapitops.plan.api.exceptions.connection.WebException;
import com.djrapitops.plan.system.processing.Processing;
import com.djrapitops.plan.system.settings.Settings;
import com.djrapitops.plan.system.webserver.cache.PageId;
import com.djrapitops.plan.system.webserver.cache.ResponseCache;
import com.djrapitops.plan.system.webserver.response.DefaultResponses;
import com.djrapitops.plan.system.webserver.response.Response;
import com.djrapitops.plan.system.webserver.response.cache.PageId;
import com.djrapitops.plan.system.webserver.response.cache.ResponseCache;
import com.djrapitops.plan.system.webserver.response.pages.AnalysisPageResponse;
import com.djrapitops.plan.utilities.Base64Util;
import com.djrapitops.plan.utilities.file.export.HtmlExport;
@ -50,13 +50,13 @@ public class CacheAnalysisPageRequest extends InfoRequestWithVariables implement
public Response handleRequest(Map<String, String> variables) throws WebException {
// Available variables: sender, html (Base64)
UUID serverUUID = UUID.fromString(variables.get("sender"));
UUID sender = UUID.fromString(variables.get("sender"));
String html = variables.get("html");
Verify.nullCheck(html, () -> new BadRequestException("HTML 'html' variable not supplied in the request"));
String sentHtml = variables.get("html");
Verify.nullCheck(sentHtml, () -> new BadRequestException("HTML 'html' variable not supplied in the request"));
boolean export = Settings.ANALYSIS_EXPORT.isTrue();
cache(export, serverUUID, Base64Util.decode(html));
cache(export, sender, Base64Util.decode(sentHtml));
return DefaultResponses.SUCCESS.get();
}

View File

@ -9,10 +9,10 @@ import com.djrapitops.plan.api.exceptions.connection.WebException;
import com.djrapitops.plan.system.info.server.ServerInfo;
import com.djrapitops.plan.system.processing.Processing;
import com.djrapitops.plan.system.settings.Settings;
import com.djrapitops.plan.system.webserver.cache.PageId;
import com.djrapitops.plan.system.webserver.cache.ResponseCache;
import com.djrapitops.plan.system.webserver.response.DefaultResponses;
import com.djrapitops.plan.system.webserver.response.Response;
import com.djrapitops.plan.system.webserver.response.cache.PageId;
import com.djrapitops.plan.system.webserver.response.cache.ResponseCache;
import com.djrapitops.plan.system.webserver.response.pages.InspectPageResponse;
import com.djrapitops.plan.utilities.Base64Util;
import com.djrapitops.plan.utilities.file.export.HtmlExport;

View File

@ -7,10 +7,10 @@ package com.djrapitops.plan.system.info.request;
import com.djrapitops.plan.api.exceptions.connection.BadRequestException;
import com.djrapitops.plan.api.exceptions.connection.WebException;
import com.djrapitops.plan.system.info.server.ServerInfo;
import com.djrapitops.plan.system.webserver.cache.PageId;
import com.djrapitops.plan.system.webserver.cache.ResponseCache;
import com.djrapitops.plan.system.webserver.response.DefaultResponses;
import com.djrapitops.plan.system.webserver.response.Response;
import com.djrapitops.plan.system.webserver.response.cache.PageId;
import com.djrapitops.plan.system.webserver.response.cache.ResponseCache;
import com.djrapitops.plan.system.webserver.response.pages.parts.InspectPagePluginsContent;
import com.djrapitops.plan.utilities.Base64Util;
import com.djrapitops.plugin.utilities.Verify;

View File

@ -6,12 +6,11 @@ package com.djrapitops.plan.system.info.request;
import com.djrapitops.plan.api.exceptions.connection.BadRequestException;
import com.djrapitops.plan.api.exceptions.connection.WebException;
import com.djrapitops.plan.system.info.InfoSystem;
import com.djrapitops.plan.system.info.server.ServerInfo;
import com.djrapitops.plan.system.webserver.cache.PageId;
import com.djrapitops.plan.system.webserver.cache.ResponseCache;
import com.djrapitops.plan.system.webserver.response.DefaultResponses;
import com.djrapitops.plan.system.webserver.response.Response;
import com.djrapitops.plan.system.webserver.response.cache.PageId;
import com.djrapitops.plan.system.webserver.response.cache.ResponseCache;
import com.djrapitops.plan.system.webserver.response.pages.parts.NetworkPageContent;
import com.djrapitops.plan.utilities.Base64Util;
import com.djrapitops.plugin.utilities.Verify;
@ -52,8 +51,8 @@ public class CacheNetworkPageContentRequest extends InfoRequestWithVariables imp
NetworkPageContent serversTab = getNetworkPageContent();
serversTab.addElement(serverName, Base64Util.decode(html));
InfoSystem.getInstance().updateNetworkPage();
ResponseCache.clearResponse(PageId.SERVER.of(ServerInfo.getServerUUID()));
return DefaultResponses.SUCCESS.get();
}

View File

@ -12,9 +12,9 @@ import com.djrapitops.plan.data.store.containers.AnalysisContainer;
import com.djrapitops.plan.system.cache.CacheSystem;
import com.djrapitops.plan.system.info.InfoSystem;
import com.djrapitops.plan.system.info.server.ServerInfo;
import com.djrapitops.plan.system.webserver.pages.parsing.AnalysisPage;
import com.djrapitops.plan.system.webserver.response.DefaultResponses;
import com.djrapitops.plan.system.webserver.response.Response;
import com.djrapitops.plan.utilities.html.pages.AnalysisPage;
import com.djrapitops.plugin.api.utility.log.Log;
import com.djrapitops.plugin.utilities.Verify;

View File

@ -8,10 +8,10 @@ import com.djrapitops.plan.api.exceptions.ParseException;
import com.djrapitops.plan.api.exceptions.connection.*;
import com.djrapitops.plan.api.exceptions.database.DBException;
import com.djrapitops.plan.system.info.InfoSystem;
import com.djrapitops.plan.system.webserver.pages.parsing.InspectPage;
import com.djrapitops.plan.system.webserver.response.DefaultResponses;
import com.djrapitops.plan.system.webserver.response.Response;
import com.djrapitops.plan.system.webserver.response.errors.NotFoundResponse;
import com.djrapitops.plan.utilities.html.pages.InspectPage;
import com.djrapitops.plugin.utilities.Verify;
import java.util.Map;

View File

@ -10,7 +10,7 @@ import com.djrapitops.plan.api.exceptions.connection.WebException;
import com.djrapitops.plan.system.settings.Settings;
import com.djrapitops.plan.system.webserver.response.DefaultResponses;
import com.djrapitops.plan.system.webserver.response.Response;
import com.djrapitops.plan.system.webserver.response.api.BadRequestResponse;
import com.djrapitops.plan.system.webserver.response.errors.BadRequestResponse;
import com.djrapitops.plugin.api.Check;
import com.djrapitops.plugin.api.TimeAmount;
import com.djrapitops.plugin.api.utility.log.Log;

View File

@ -13,7 +13,7 @@ import com.djrapitops.plan.system.info.server.Server;
import com.djrapitops.plan.system.settings.Settings;
import com.djrapitops.plan.system.webserver.response.DefaultResponses;
import com.djrapitops.plan.system.webserver.response.Response;
import com.djrapitops.plan.system.webserver.response.api.BadRequestResponse;
import com.djrapitops.plan.system.webserver.response.errors.BadRequestResponse;
import com.djrapitops.plugin.api.Check;
import com.djrapitops.plugin.utilities.Verify;

View File

@ -8,7 +8,7 @@ import com.djrapitops.plan.system.settings.Settings;
import com.djrapitops.plan.system.update.ShutdownUpdateHook;
import com.djrapitops.plan.system.webserver.response.DefaultResponses;
import com.djrapitops.plan.system.webserver.response.Response;
import com.djrapitops.plan.system.webserver.response.api.BadRequestResponse;
import com.djrapitops.plan.system.webserver.response.errors.BadRequestResponse;
import java.util.Map;

View File

@ -6,11 +6,13 @@ package com.djrapitops.plan.system.listeners.bungee;
import com.djrapitops.plan.data.container.Session;
import com.djrapitops.plan.system.cache.SessionCache;
import com.djrapitops.plan.system.info.server.ServerInfo;
import com.djrapitops.plan.system.processing.Processing;
import com.djrapitops.plan.system.processing.processors.info.NetworkPageUpdateProcessor;
import com.djrapitops.plan.system.processing.processors.info.PlayerPageUpdateProcessor;
import com.djrapitops.plan.system.processing.processors.player.BungeePlayerRegisterProcessor;
import com.djrapitops.plan.system.processing.processors.player.IPUpdateProcessor;
import com.djrapitops.plan.system.webserver.cache.PageId;
import com.djrapitops.plan.system.webserver.cache.ResponseCache;
import com.djrapitops.plugin.api.utility.log.Log;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.PostLoginEvent;
@ -44,7 +46,7 @@ public class PlayerOnlineListener implements Listener {
new IPUpdateProcessor(uuid, address, now))
);
Processing.submit(new PlayerPageUpdateProcessor(uuid));
Processing.submit(new NetworkPageUpdateProcessor());
ResponseCache.clearResponse(PageId.SERVER.of(ServerInfo.getServerUUID()));
} catch (Exception e) {
Log.toLog(this.getClass(), e);
}
@ -58,7 +60,7 @@ public class PlayerOnlineListener implements Listener {
SessionCache.getInstance().endSession(uuid, System.currentTimeMillis());
Processing.submit(new PlayerPageUpdateProcessor(uuid));
Processing.submit(new NetworkPageUpdateProcessor());
ResponseCache.clearResponse(PageId.SERVER.of(ServerInfo.getServerUUID()));
} catch (Exception e) {
Log.toLog(this.getClass(), e);
}

View File

@ -40,7 +40,8 @@ public enum CmdHelpLang implements Lang {
WEB_LIST("Command Help - /plan web list", "List Web Users"),
WEB_CHECK("Command Help - /plan web check", "Inspect a Web User"),
WEB_DELETE("Command Help - /plan web delete", "Delete a Web User"),
MANAGE_RAW_DATA("Command Help - /plan manage raw", "View raw JSON of player data");
MANAGE_RAW_DATA("Command Help - /plan manage raw", "View raw JSON of player data"),
MANAGE_UNINSTALLED("Command Help - /plan manage uninstalled", "Mark a server as uninstalled in the database.");
private final String identifier;
private final String defaultValue;

View File

@ -32,7 +32,8 @@ public enum DeepHelpLang implements Lang {
MANAGE_SETUP("In Depth Help - /plan manage setup ?", "> §2Setup Subcommand\\ Set-up a connection between Bungee and this server for network functionality.\\ BungeeAddress can be found in the enable log on console when Plan enables on Bungee."),
WEB_REGISTER("In Depth Help - /plan web register ?", "> §2Register Subcommand\\ Registers a new Web User.\\ Registering a user for another player requires plan.webmanage permission.\\ Passwords are hashed with PBKDF2 (64,000 iterations of SHA1) using a cryptographically-random salt."),
MANAGE_RAW_DATA("In Depth Help - /plan manage raw ?", "> §2Raw Data Subcommand\\ Displays link to raw JSON data page.\\ Not available if Plan webserver is not enabled.");
MANAGE_RAW_DATA("In Depth Help - /plan manage raw ?", "> §2Raw Data Subcommand\\ Displays link to raw JSON data page.\\ Not available if Plan webserver is not enabled."),
MANAGE_UNINSTALLED("In Depth Help - /plan manage uninstalled ?", "> §2Uninstalled Server Subcommand\\ Marks a server as uninstalled in the database.\\ Can not mark the server the command is being used on as uninstalled.\\ Will affect ConnectionSystem.");
private final String identifier;
private final String defaultValue;

View File

@ -18,7 +18,10 @@ public enum ErrorPageLang implements Lang {
NOT_FOUND_404("Not Found"),
PAGE_NOT_FOUND_404("Page does not exist."),
ANALYSIS_REFRESH("Analysis is being refreshed.."),
ANALYSIS_REFRESH_LONG("Analysis is being run, refresh the page after a few seconds..");
ANALYSIS_REFRESH_LONG("Analysis is being run, refresh the page after a few seconds.."),
INSPECT_REFRESH("Player page request is being processed.."),
INSPECT_REFRESH_LONG("Page will refresh automatically.."),
PLUGIN_TAB_REFRESH("Calculating...");
private final String defaultValue;

View File

@ -28,7 +28,9 @@ public enum ManageLang implements Lang {
FAIL_SAME_DB("Manage - Fail Same Database", "> §cCan not operate on to and from the same database!"),
FAIL_INCORRECT_DB("Manage - Fail Incorrect Database", "> §c'${0}' is not a supported database."),
FAIL_FILE_NOT_FOUND("Manage - Fail File not found", "> §cNo File found at ${0}"),
FAIL_IMPORTER_NOT_FOUND("Manage - Fail No Importer", "§eImporter '${0}' doesn't exist");
FAIL_IMPORTER_NOT_FOUND("Manage - Fail No Importer", "§eImporter '${0}' doesn't exist"),
NO_SERVER("Manage - Fail No Server", "No server found with given parameters."),
UNINSTALLING_SAME_SERVER("Manage - Fail Same server", "Can not mark this server as uninstalled (You are on it)");
private final String identifier;
private final String defaultValue;

View File

@ -32,13 +32,7 @@ public class PlanErrorManager implements ErrorManager {
} else {
Log.warn("It has been logged to ErrorLog.txt");
}
try {
if ((Check.isBukkitAvailable() && Check.isBungeeAvailable()) || Settings.DEV_MODE.isTrue()) {
Logger.getGlobal().log(Level.WARNING, source, e);
}
} catch (IllegalStateException ignored) {
/* Config system not initialized */
}
logGlobally(source, e);
ErrorLogger.logThrowable(e, logsFolder);
} catch (Exception exception) {
System.out.println("Failed to log error to file because of " + exception);
@ -48,4 +42,14 @@ public class PlanErrorManager implements ErrorManager {
Logger.getGlobal().log(Level.WARNING, source, e);
}
}
private void logGlobally(String source, Throwable e) {
try {
if ((Check.isBukkitAvailable() && Check.isBungeeAvailable()) || Settings.DEV_MODE.isTrue()) {
Logger.getGlobal().log(Level.WARNING, source, e);
}
} catch (IllegalStateException ignored) {
/* Config system not initialized */
}
}
}

View File

@ -30,11 +30,13 @@ public class BukkitTaskSystem extends ServerTaskSystem {
@Override
public void enable() {
super.enable();
if (Check.isSpigotAvailable()) {
try {
PingCountTimer pingCountTimer = new PingCountTimer();
((Plan) plugin).registerListener(pingCountTimer);
RunnableFactory.createNew("PingCountTimer", pingCountTimer)
.runTaskTimer(20L, PingCountTimer.PING_INTERVAL);
} catch (ExceptionInInitializerError | NoClassDefFoundError ignore) {
// Running CraftBukkit
}
}

View File

@ -9,11 +9,10 @@ import com.djrapitops.plan.api.exceptions.connection.*;
import com.djrapitops.plan.system.info.connection.InfoRequestPageHandler;
import com.djrapitops.plan.system.locale.lang.ErrorPageLang;
import com.djrapitops.plan.system.webserver.auth.Authentication;
import com.djrapitops.plan.system.webserver.cache.PageId;
import com.djrapitops.plan.system.webserver.cache.ResponseCache;
import com.djrapitops.plan.system.webserver.pages.*;
import com.djrapitops.plan.system.webserver.response.*;
import com.djrapitops.plan.system.webserver.response.api.BadRequestResponse;
import com.djrapitops.plan.system.webserver.response.cache.PageId;
import com.djrapitops.plan.system.webserver.response.cache.ResponseCache;
import com.djrapitops.plan.system.webserver.response.errors.*;
import com.djrapitops.plugin.api.utility.log.Log;

View File

@ -8,7 +8,7 @@ import com.djrapitops.plan.api.exceptions.EnableException;
import com.djrapitops.plan.system.PlanSystem;
import com.djrapitops.plan.system.SubSystem;
import com.djrapitops.plan.system.locale.Locale;
import com.djrapitops.plan.system.webserver.response.cache.ResponseCache;
import com.djrapitops.plan.system.webserver.cache.ResponseCache;
import com.djrapitops.plugin.api.Benchmark;
import java.util.function.Supplier;

View File

@ -2,7 +2,7 @@
* License is provided in the jar as LICENSE also here:
* https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/LICENSE
*/
package com.djrapitops.plan.system.webserver.response.cache;
package com.djrapitops.plan.system.webserver.cache;
import java.util.UUID;

View File

@ -1,4 +1,4 @@
package com.djrapitops.plan.system.webserver.response.cache;
package com.djrapitops.plan.system.webserver.cache;
import com.djrapitops.plan.system.webserver.response.Response;
@ -97,4 +97,8 @@ public class ResponseCache {
public static Set<String> getCacheKeys() {
return cache.keySet();
}
public static void clearResponse(String identifier) {
cache.remove(identifier);
}
}

View File

@ -14,9 +14,9 @@ import com.djrapitops.plan.system.locale.Locale;
import com.djrapitops.plan.system.locale.lang.ErrorPageLang;
import com.djrapitops.plan.system.webserver.Request;
import com.djrapitops.plan.system.webserver.auth.Authentication;
import com.djrapitops.plan.system.webserver.cache.PageId;
import com.djrapitops.plan.system.webserver.cache.ResponseCache;
import com.djrapitops.plan.system.webserver.response.Response;
import com.djrapitops.plan.system.webserver.response.cache.PageId;
import com.djrapitops.plan.system.webserver.response.cache.ResponseCache;
import com.djrapitops.plan.system.webserver.response.errors.NotFoundResponse;
import com.djrapitops.plan.system.webserver.response.pages.InspectPageResponse;
import com.djrapitops.plan.system.webserver.response.pages.RawPlayerDataResponse;

View File

@ -7,9 +7,9 @@ package com.djrapitops.plan.system.webserver.pages;
import com.djrapitops.plan.api.exceptions.WebUserAuthException;
import com.djrapitops.plan.system.webserver.Request;
import com.djrapitops.plan.system.webserver.auth.Authentication;
import com.djrapitops.plan.system.webserver.cache.PageId;
import com.djrapitops.plan.system.webserver.cache.ResponseCache;
import com.djrapitops.plan.system.webserver.response.Response;
import com.djrapitops.plan.system.webserver.response.cache.PageId;
import com.djrapitops.plan.system.webserver.response.cache.ResponseCache;
import com.djrapitops.plan.system.webserver.response.pages.PlayersPageResponse;
import java.util.List;

View File

@ -11,9 +11,9 @@ import com.djrapitops.plan.system.info.InfoSystem;
import com.djrapitops.plan.system.info.server.ServerInfo;
import com.djrapitops.plan.system.webserver.Request;
import com.djrapitops.plan.system.webserver.auth.Authentication;
import com.djrapitops.plan.system.webserver.cache.PageId;
import com.djrapitops.plan.system.webserver.cache.ResponseCache;
import com.djrapitops.plan.system.webserver.response.Response;
import com.djrapitops.plan.system.webserver.response.cache.PageId;
import com.djrapitops.plan.system.webserver.response.cache.ResponseCache;
import com.djrapitops.plan.system.webserver.response.pages.AnalysisPageResponse;
import com.djrapitops.plan.system.webserver.response.pages.RawServerDataResponse;
import com.djrapitops.plugin.api.Check;

View File

@ -4,8 +4,6 @@
*/
package com.djrapitops.plan.system.webserver.response;
import com.djrapitops.plan.system.webserver.response.api.SuccessResponse;
/**
* Enum containing default responses that don't need to be cached because they're always the same.
*
@ -13,7 +11,7 @@ import com.djrapitops.plan.system.webserver.response.api.SuccessResponse;
*/
public enum DefaultResponses {
BASIC_AUTH(PromptAuthorizationResponse.getBasicAuthResponse()),
SUCCESS(new SuccessResponse());
SUCCESS(new TextResponse("Success"));
private final Response response;

View File

@ -0,0 +1,14 @@
package com.djrapitops.plan.system.webserver.response;
/**
* Response for raw text.
*
* @author Rsl1122
*/
public class TextResponse extends Response {
public TextResponse(String content) {
setHeader("HTTP/1.1 200 OK");
setContent(content);
}
}

View File

@ -1,23 +0,0 @@
/*
* License is provided in the jar as LICENSE also here:
* https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/LICENSE
*/
package com.djrapitops.plan.system.webserver.response.api;
import com.djrapitops.plan.system.webserver.response.Response;
import com.djrapitops.plan.system.webserver.response.ResponseType;
import com.google.gson.Gson;
/**
* @author Fuzzlemann
*/
public class JsonResponse extends Response {
public <T> JsonResponse(T object) {
super(ResponseType.JSON);
Gson gson = new Gson();
super.setHeader("HTTP/1.1 200 OK");
super.setContent(gson.toJson(object));
}
}

View File

@ -1,18 +0,0 @@
/*
* License is provided in the jar as LICENSE also here:
* https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/LICENSE
*/
package com.djrapitops.plan.system.webserver.response.api;
import com.djrapitops.plan.system.webserver.response.Response;
/**
* @author Fuzzlemann
*/
public class SuccessResponse extends Response {
public SuccessResponse() {
super.setHeader("HTTP/1.1 200 OK");
super.setContent("Success");
}
}

View File

@ -2,7 +2,7 @@
* License is provided in the jar as LICENSE also here:
* https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/LICENSE
*/
package com.djrapitops.plan.system.webserver.response.api;
package com.djrapitops.plan.system.webserver.response.errors;
import com.djrapitops.plan.system.webserver.response.Response;

View File

@ -5,11 +5,11 @@ import com.djrapitops.plan.api.exceptions.connection.NoServersException;
import com.djrapitops.plan.api.exceptions.connection.WebException;
import com.djrapitops.plan.system.info.InfoSystem;
import com.djrapitops.plan.system.processing.Processing;
import com.djrapitops.plan.system.webserver.pages.parsing.AnalysisPage;
import com.djrapitops.plan.system.webserver.cache.PageId;
import com.djrapitops.plan.system.webserver.cache.ResponseCache;
import com.djrapitops.plan.system.webserver.response.Response;
import com.djrapitops.plan.system.webserver.response.cache.PageId;
import com.djrapitops.plan.system.webserver.response.cache.ResponseCache;
import com.djrapitops.plan.system.webserver.response.errors.NotFoundResponse;
import com.djrapitops.plan.utilities.html.pages.AnalysisPage;
import com.djrapitops.plugin.api.utility.log.Log;
import java.util.UUID;

View File

@ -4,40 +4,9 @@
*/
package com.djrapitops.plan.system.webserver.response.pages;
import com.djrapitops.plan.PlanPlugin;
import com.djrapitops.plan.data.container.Session;
import com.djrapitops.plan.data.store.CachingSupplier;
import com.djrapitops.plan.data.store.Key;
import com.djrapitops.plan.data.store.keys.SessionKeys;
import com.djrapitops.plan.data.store.mutators.formatting.Formatter;
import com.djrapitops.plan.data.store.mutators.formatting.Formatters;
import com.djrapitops.plan.data.store.objects.DateHolder;
import com.djrapitops.plan.system.cache.CacheSystem;
import com.djrapitops.plan.system.cache.SessionCache;
import com.djrapitops.plan.system.database.databases.Database;
import com.djrapitops.plan.system.info.connection.ConnectionLog;
import com.djrapitops.plan.system.info.connection.ConnectionSystem;
import com.djrapitops.plan.system.info.server.Server;
import com.djrapitops.plan.system.info.server.ServerInfo;
import com.djrapitops.plan.system.info.server.properties.ServerProperties;
import com.djrapitops.plan.system.webserver.response.cache.ResponseCache;
import com.djrapitops.plan.system.webserver.response.errors.ErrorResponse;
import com.djrapitops.plan.utilities.file.FileUtil;
import com.djrapitops.plan.utilities.html.Html;
import com.djrapitops.plan.utilities.html.HtmlStructure;
import com.djrapitops.plan.utilities.html.icon.Icon;
import com.djrapitops.plan.utilities.html.structure.TabsElement;
import com.djrapitops.plugin.api.Benchmark;
import com.djrapitops.plugin.api.utility.log.ErrorLogger;
import com.djrapitops.plugin.api.utility.log.Log;
import java.io.File;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.nio.charset.Charset;
import java.util.*;
import java.util.function.Supplier;
import com.djrapitops.plan.utilities.html.pages.DebugPage;
/**
* WebServer response for /debug-page used for easing issue reporting.
@ -49,288 +18,8 @@ public class DebugPageResponse extends ErrorResponse {
public DebugPageResponse() {
super.setHeader("HTTP/1.1 200 OK");
super.setTitle(Icon.called("bug") + " Debug Information");
super.setParagraph(buildContent());
super.setParagraph(new DebugPage().toHtml());
replacePlaceholders();
}
private String buildContent() {
StringBuilder preContent = new StringBuilder();
String issueLink = Html.LINK_EXTERNAL.parse("https://github.com/Rsl1122/Plan-PlayerAnalytics/issues/new", "Create new issue on Github");
String hastebinLink = Html.LINK_EXTERNAL.parse("https://hastebin.com/", "Create a new hastebin paste");
preContent.append("<p>")
.append(HtmlStructure.separateWithDots(issueLink, hastebinLink)).append("<br><br>")
.append("This page contains debug information for an issue ticket. You can copy it directly into the issue, the info is pre-formatted.")
.append("</p>");
TabsElement.Tab info = new TabsElement.Tab(Icon.called("server") + " Server Information", createServerInfoContent());
TabsElement.Tab errors = new TabsElement.Tab(Icon.called("exclamation-circle") + " Errors", createErrorContent());
TabsElement.Tab debugLog = new TabsElement.Tab(Icon.called("bug") + " Debug Log", createDebugLogContent());
TabsElement.Tab config = new TabsElement.Tab(Icon.called("cogs") + " Plan Config", createConfigContent());
TabsElement.Tab caches = new TabsElement.Tab(Icon.called("archive") + " Plan Caches", createCacheContent());
TabsElement tabs = new TabsElement(info, errors, debugLog, config, caches);
return preContent + tabs.toHtmlFull();
}
private String createCacheContent() {
StringBuilder content = new StringBuilder();
appendResponseCache(content);
appendSessionCache(content);
appendDataContainerCache(content);
return content.toString();
}
private void appendResponseCache(StringBuilder content) {
try {
content.append("<pre>### Cached Responses:<br><br>");
List<String> cacheKeys = new ArrayList<>(ResponseCache.getCacheKeys());
if (cacheKeys.isEmpty()) {
content.append("Empty");
}
Collections.sort(cacheKeys);
for (String cacheKey : cacheKeys) {
content.append("- ").append(cacheKey).append("<br>");
}
content.append("</pre>");
} catch (Exception e) {
Log.toLog(this.getClass(), e);
}
}
private void appendSessionCache(StringBuilder content) {
try {
content.append("<pre>### Session Cache:<br><br>");
content.append("UUID | Session Started <br>")
.append("-- | -- <br>");
Formatter<Long> timeStamp = Formatters.yearLongValue();
Set<Map.Entry<UUID, Session>> sessions = SessionCache.getActiveSessions().entrySet();
if (sessions.isEmpty()) {
content.append("Empty");
}
for (Map.Entry<UUID, Session> entry : sessions) {
UUID uuid = entry.getKey();
String start = entry.getValue().getValue(SessionKeys.START).map(timeStamp).orElse("Unknown");
content.append(uuid.toString()).append(" | ").append(start).append("<br>");
}
content.append("</pre>");
} catch (Exception e) {
Log.toLog(this.getClass(), e);
}
}
private void appendDataContainerCache(StringBuilder content) {
try {
content.append("<pre>### DataContainer Cache:<br><br>");
content.append("Key | Is Cached | Cache Time <br>")
.append("-- | -- | -- <br>");
Formatter<Long> timeStamp = Formatters.yearLongValue();
Set<Map.Entry<Key, Supplier>> dataContainers = CacheSystem.getInstance().getDataContainerCache().getMap().entrySet();
if (dataContainers.isEmpty()) {
content.append("Empty");
}
for (Map.Entry<Key, Supplier> entry : dataContainers) {
String keyName = entry.getKey().getKeyName();
Supplier supplier = entry.getValue();
if (supplier instanceof CachingSupplier) {
CachingSupplier cachingSupplier = (CachingSupplier) supplier;
boolean isCached = cachingSupplier.isCached();
String cacheText = isCached ? "Yes" : "No";
String cacheTime = isCached ? timeStamp.apply(cachingSupplier.getCacheTime()) : "-";
content.append(keyName).append(" | ").append(cacheText).append(" | ").append(cacheTime).append("<br>");
} else {
content.append(keyName).append(" | ").append("Non-caching Supplier").append(" | ").append("-").append("<br>");
}
}
content.append("</pre>");
} catch (Exception e) {
Log.toLog(this.getClass(), e);
}
}
private String createConfigContent() {
StringBuilder content = new StringBuilder();
appendConfig(content);
return content.toString();
}
private String createDebugLogContent() {
StringBuilder content = new StringBuilder();
appendDebugLog(content);
return content.toString();
}
private String createErrorContent() {
StringBuilder content = new StringBuilder();
appendLoggedErrors(content);
return content.toString();
}
private String createServerInfoContent() {
StringBuilder content = new StringBuilder();
appendServerInformation(content);
appendConnectionLog(content);
appendBenchmarks(content);
return content.toString();
}
private void appendConnectionLog(StringBuilder content) {
try {
Map<String, Map<String, ConnectionLog.Entry>> logEntries = ConnectionLog.getLogEntries();
content.append("<pre>### Connection Log:<br><br>");
content.append("Server Address | Request Type | Response | Sent<br>")
.append("-- | -- | -- | --<br>");
Formatter<DateHolder> formatter = Formatters.second();
if (logEntries.isEmpty()) {
content.append("**No Connections Logged**<br>");
}
for (Map.Entry<String, Map<String, ConnectionLog.Entry>> entry : logEntries.entrySet()) {
String address = entry.getKey();
Map<String, ConnectionLog.Entry> requests = entry.getValue();
for (Map.Entry<String, ConnectionLog.Entry> requestEntry : requests.entrySet()) {
String infoRequest = requestEntry.getKey();
ConnectionLog.Entry logEntry = requestEntry.getValue();
content.append(address).append(" | ")
.append(infoRequest).append(" | ")
.append(logEntry.getResponseCode()).append(" | ")
.append(formatter.apply(logEntry)).append("<br>");
}
}
content.append("</pre>");
content.append("<pre>### Servers:<br><br>");
List<Server> servers = ConnectionSystem.getInstance().getBukkitServers();
content.append("Server Name | Address | UUID <br>")
.append("-- | -- | --<br>");
for (Server server : servers) {
content.append(server.getName()).append(" | ")
.append(server.getWebAddress()).append(" | ")
.append(server.getUuid()).append("<br>");
}
content.append("</pre>");
} catch (Exception e) {
Log.toLog(this.getClass(), e);
}
}
private void appendServerInformation(StringBuilder content) {
PlanPlugin plugin = PlanPlugin.getInstance();
ServerProperties variable = ServerInfo.getServerProperties();
content.append("<pre>### Server Information<br>")
.append("**Plan Version:** ").append(plugin.getVersion()).append("<br>");
content.append("**Server:** ");
content.append(variable.getName())
.append(" ").append(variable.getImplVersion())
.append(" ").append(variable.getVersion());
content.append("<br>");
Database database = Database.getActive();
content.append("**Database:** ").append(database.getName());
content.append("<br><br>");
RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
Properties properties = System.getProperties();
String osName = properties.getProperty("os.name");
String osVersion = properties.getProperty("os.version");
String osArch = properties.getProperty("os.arch");
String javaVendor = properties.getProperty("java.vendor");
String javaVersion = properties.getProperty("java.version");
String javaVMVendor = properties.getProperty("java.vm.vendor");
String javaVMName = properties.getProperty("java.vm.name");
String javaVMVersion = properties.getProperty("java.vm.version");
List<String> javaVMFlags = runtimeMxBean.getInputArguments();
content.append("**Operating SubSystem:** ").append(osName).append(" (").append(osArch)
.append(") version ").append(osVersion).append("<br>");
content.append("**Java Version:** ").append(javaVersion).append(", ").append(javaVendor).append("<br>");
content.append("**Java VM Version:** ").append(javaVMName).append(" version ").append(javaVMVersion)
.append(", ").append(javaVMVendor).append("<br>");
content.append("**Java VM Flags:** ").append(javaVMFlags).append("<br>");
content.append("</pre>");
}
private void appendConfig(StringBuilder content) {
try {
File configFile = new File(PlanPlugin.getInstance().getDataFolder(), "config.yml");
if (configFile.exists()) {
content.append("<pre>### config.yml<br>&#96;&#96;&#96;<br>");
FileUtil.lines(configFile, Charset.forName("UTF-8"))
.stream().filter(line -> !line.toLowerCase().contains("pass") && !line.toLowerCase().contains("secret"))
.forEach(line -> content.append(line).append("<br>"));
content.append("&#96;&#96;&#96;</pre>");
}
} catch (IOException e) {
Log.toLog(this.getClass(), e);
}
}
private void appendBenchmarks(StringBuilder content) {
content.append("<pre>### Benchmarks<br>&#96;&#96;&#96;<br>");
try {
for (String line : Benchmark.getAverages().asStringArray()) {
content.append(line).append("<br>");
}
} catch (Exception e) {
content.append("Exception on Benchmark.getAverages().asStringArray()");
}
content.append("&#96;&#96;&#96;</pre>");
}
private void appendLoggedErrors(StringBuilder content) {
try {
content.append("<pre>### Logged Errors<br>");
SortedMap<String, List<String>> errors = ErrorLogger.getLoggedErrors(PlanPlugin.getInstance());
if (!errors.isEmpty()) {
List<String> errorLines = new ArrayList<>();
for (Map.Entry<String, List<String>> entry : errors.entrySet()) {
StringBuilder errorLineBuilder = new StringBuilder();
for (String line : entry.getValue()) {
errorLineBuilder.append(line).append("<br>");
}
String error = errorLineBuilder.toString();
if (!errorLines.contains(error)) {
errorLines.add(error);
}
}
for (String error : errorLines) {
content.append("</pre><pre>&#96;&#96;&#96;<br>")
.append(error)
.append("&#96;&#96;&#96;");
}
} else {
content.append("**No Errors logged.**<br>");
}
content.append("</pre>");
} catch (IOException e) {
Log.toLog(this.getClass(), e);
}
}
private void appendDebugLog(StringBuilder content) {
content.append("<pre>### Debug Log<br>&#96;&#96;&#96;<br>");
for (String line : Log.getDebugLogInMemory()) {
content.append(line).append("<br>");
}
content.append("&#96;&#96;&#96;</pre>");
}
}

View File

@ -1,9 +1,9 @@
package com.djrapitops.plan.system.webserver.response.pages;
import com.djrapitops.plan.system.settings.theme.Theme;
import com.djrapitops.plan.system.webserver.cache.PageId;
import com.djrapitops.plan.system.webserver.cache.ResponseCache;
import com.djrapitops.plan.system.webserver.response.Response;
import com.djrapitops.plan.system.webserver.response.cache.PageId;
import com.djrapitops.plan.system.webserver.response.cache.ResponseCache;
import com.djrapitops.plan.system.webserver.response.errors.ErrorResponse;
import com.djrapitops.plan.system.webserver.response.pages.parts.InspectPagePluginsContent;
import org.apache.commons.text.StringSubstitutor;

View File

@ -0,0 +1,21 @@
package com.djrapitops.plan.system.webserver.response.pages;
import com.djrapitops.plan.api.exceptions.ParseException;
import com.djrapitops.plan.data.store.containers.NetworkContainer;
import com.djrapitops.plan.system.database.databases.Database;
import com.djrapitops.plan.system.webserver.response.Response;
import com.djrapitops.plan.utilities.html.pages.NetworkPage;
/**
* Response for /network page.
*
* @author Rsl1122
*/
public class NetworkPageResponse extends Response {
public NetworkPageResponse() throws ParseException {
super.setHeader("HTTP/1.1 200 OK");
NetworkContainer networkContainer = Database.getActive().fetch().getNetworkContainer(); // Not cached, big.
setContent(new NetworkPage(networkContainer).toHtml());
}
}

View File

@ -1,9 +1,9 @@
package com.djrapitops.plan.system.webserver.response.pages;
import com.djrapitops.plan.api.exceptions.ParseException;
import com.djrapitops.plan.system.webserver.pages.parsing.PlayersPage;
import com.djrapitops.plan.system.webserver.response.Response;
import com.djrapitops.plan.system.webserver.response.errors.InternalErrorResponse;
import com.djrapitops.plan.utilities.html.pages.PlayersPage;
import com.djrapitops.plugin.api.utility.log.Log;
/**

View File

@ -1,126 +0,0 @@
package com.djrapitops.plan.utilities.analysis;
import com.djrapitops.plan.data.container.Session;
import com.djrapitops.plan.data.store.keys.SessionKeys;
import com.djrapitops.plan.data.store.mutators.RetentionData;
import com.djrapitops.plan.data.time.WorldTimes;
import com.djrapitops.plan.system.settings.WorldAliasSettings;
import com.djrapitops.plan.utilities.FormatUtils;
import java.util.*;
import java.util.stream.Collectors;
/**
* Class that contains various methods that are used in analysis.
*
* @author Rsl1122
*/
public class AnalysisUtils {
private AnalysisUtils() {
/* static method class.*/
}
/**
* Transforms the session start list into a list of int arrays.
* <p>
* First number signifies the Day of Week. (0 = Monday, 6 = Sunday)
* Second number signifies the Hour of Day. (0 = 0 AM, 23 = 11 PM)
*
* @param sessionStarts List of Session start Epoch ms.
* @return list of int arrays.
*/
public static List<int[]> getDaysAndHours(List<Long> sessionStarts) {
return sessionStarts.stream().map((Long start) -> {
Calendar day = Calendar.getInstance();
day.setTimeInMillis(start);
int hourOfDay = day.get(Calendar.HOUR_OF_DAY); // 0 AM is 0
int dayOfWeek = day.get(Calendar.DAY_OF_WEEK) - 2; // Monday is 0, Sunday is -1
if (hourOfDay == 24) { // If hour is 24 (Should be impossible but.)
hourOfDay = 0;
dayOfWeek += 1;
}
if (dayOfWeek > 6) { // If Hour added a day on Sunday, move to Monday
dayOfWeek = 0;
}
if (dayOfWeek < 0) { // Move Sunday to 6
dayOfWeek = 6;
}
return new int[]{dayOfWeek, hourOfDay};
}).collect(Collectors.toList());
}
public static Map<String, Long> getPlaytimePerAlias(WorldTimes worldTimes) {
// WorldTimes Map<String, GMTimes>
Map<String, Long> playtimePerWorld = worldTimes.getWorldTimes()
.entrySet().stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
entry -> entry.getValue().getTotal() // GMTimes.getTotal
));
Map<String, String> aliases = WorldAliasSettings.getAliases();
Map<String, Long> playtimePerAlias = new HashMap<>();
for (Map.Entry<String, Long> entry : playtimePerWorld.entrySet()) {
String worldName = entry.getKey();
long playtime = entry.getValue();
if (!aliases.containsKey(worldName)) {
aliases.put(worldName, worldName);
WorldAliasSettings.addWorld(worldName);
}
String alias = aliases.get(worldName);
playtimePerAlias.put(alias, playtimePerAlias.getOrDefault(alias, 0L) + playtime);
}
return playtimePerAlias;
}
public static RetentionData average(Collection<RetentionData> stuck) {
int size = stuck.size();
double totalIndex = 0.0;
double totalPlayersOnline = 0.0;
for (RetentionData retentionData : stuck) {
totalIndex += retentionData.getActivityIndex();
totalPlayersOnline += retentionData.getOnlineOnJoin();
}
double averageIndex = totalIndex / (double) size;
double averagePlayersOnline = totalPlayersOnline / (double) size;
return new RetentionData(averageIndex, averagePlayersOnline);
}
public static String getLongestWorldPlayed(Session session) {
Map<String, String> aliases = WorldAliasSettings.getAliases();
if (!session.supports(SessionKeys.WORLD_TIMES)) {
return "No World Time Data";
}
if (!session.supports(SessionKeys.END)) {
return "Current: " + aliases.get(session.getUnsafe(SessionKeys.WORLD_TIMES).getCurrentWorld());
}
WorldTimes worldTimes = session.getUnsafe(SessionKeys.WORLD_TIMES);
Map<String, Long> playtimePerAlias = getPlaytimePerAlias(worldTimes);
long total = worldTimes.getTotal();
long longest = 0;
String theWorld = "-";
for (Map.Entry<String, Long> entry : playtimePerAlias.entrySet()) {
String world = entry.getKey();
long time = entry.getValue();
if (time > longest) {
longest = time;
theWorld = world;
}
}
double percentage = longest * 100.0 / total;
return theWorld + " (" + FormatUtils.cutDecimals(percentage) + "%)";
}
}

View File

@ -7,9 +7,9 @@ package com.djrapitops.plan.utilities.file.export;
import com.djrapitops.plan.PlanPlugin;
import com.djrapitops.plan.system.info.server.ServerInfo;
import com.djrapitops.plan.system.settings.Settings;
import com.djrapitops.plan.system.webserver.cache.PageId;
import com.djrapitops.plan.system.webserver.cache.ResponseCache;
import com.djrapitops.plan.system.webserver.response.Response;
import com.djrapitops.plan.system.webserver.response.cache.PageId;
import com.djrapitops.plan.system.webserver.response.cache.ResponseCache;
import com.djrapitops.plugin.api.Check;
import com.djrapitops.plugin.api.utility.log.Log;
import com.djrapitops.plugin.task.AbsRunnable;

View File

@ -7,8 +7,8 @@ package com.djrapitops.plan.utilities.html.graphs;
import com.djrapitops.plan.data.container.Session;
import com.djrapitops.plan.data.store.keys.SessionKeys;
import com.djrapitops.plan.utilities.analysis.AnalysisUtils;
import java.util.Calendar;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
@ -33,11 +33,45 @@ public class PunchCardGraph implements HighChart {
this.sessions = sessions;
}
/*
* First number signifies the Day of Week. (0 = Monday, 6 = Sunday)
* Second number signifies the Hour of Day. (0 = 0 AM, 23 = 11 PM)
*/
private static List<int[]> getDaysAndHours(Collection<Long> sessionStarts) {
return sessionStarts.stream().map((Long start) -> {
Calendar day = Calendar.getInstance();
day.setTimeInMillis(start);
int hourOfDay = day.get(Calendar.HOUR_OF_DAY); // 0 AM is 0
int dayOfWeek = day.get(Calendar.DAY_OF_WEEK) - 2; // Monday is 0, Sunday is -1
if (hourOfDay == 24) { // If hour is 24 (Should be impossible but.)
hourOfDay = 0;
dayOfWeek += 1;
}
if (dayOfWeek > 6) { // If Hour added a day on Sunday, move to Monday
dayOfWeek = 0;
}
if (dayOfWeek < 0) { // Move Sunday to 6
dayOfWeek = 6;
}
return new int[]{dayOfWeek, hourOfDay};
}).collect(Collectors.toList());
}
private static int[][] turnIntoArray(Collection<Long> sessionStarts) {
List<int[]> daysAndHours = getDaysAndHours(sessionStarts);
int[][] dataArray = createEmptyArray();
for (int[] dAndH : daysAndHours) {
int d = dAndH[0];
int h = dAndH[1];
dataArray[d][h] = dataArray[d][h] + 1;
}
return dataArray;
}
@Override
public String toHighChartsSeries() {
List<Long> sessionStarts = getSessionStarts(sessions);
List<int[]> daysAndHours = AnalysisUtils.getDaysAndHours(sessionStarts);
int[][] dataArray = turnIntoArray(daysAndHours);
int[][] dataArray = turnIntoArray(sessionStarts);
int big = findBiggestValue(dataArray);
int[][] scaled = scale(dataArray, big);
StringBuilder arrayBuilder = new StringBuilder("[");
@ -62,16 +96,6 @@ public class PunchCardGraph implements HighChart {
return arrayBuilder.toString();
}
private static int[][] turnIntoArray(List<int[]> daysAndHours) {
int[][] dataArray = createEmptyArray();
for (int[] dAndH : daysAndHours) {
int d = dAndH[0];
int h = dAndH[1];
dataArray[d][h] = dataArray[d][h] + 1;
}
return dataArray;
}
private static List<Long> getSessionStarts(Collection<Session> data) {
return data.stream()
.filter(Objects::nonNull)

View File

@ -64,7 +64,7 @@ public class ServerCalendar {
private void appendSessionRelatedData(StringBuilder series) {
SessionsMutator sessionsMutator = new SessionsMutator(mutator.getSessions());
TreeMap<Long, List<Session>> byStartOfDay = sessionsMutator.toDateHoldersMutator().groupByStartOfDay();
SortedMap<Long, List<Session>> byStartOfDay = sessionsMutator.toDateHoldersMutator().groupByStartOfDay();
for (Map.Entry<Long, Integer> entry : uniquePerDay.entrySet()) {
if (entry.getValue() <= 0) {

View File

@ -6,7 +6,6 @@ import com.djrapitops.plan.system.settings.Settings;
import com.djrapitops.plan.system.settings.WorldAliasSettings;
import com.djrapitops.plan.system.settings.theme.Theme;
import com.djrapitops.plan.system.settings.theme.ThemeVal;
import com.djrapitops.plan.utilities.analysis.AnalysisUtils;
import com.djrapitops.plan.utilities.comparators.PieSliceComparator;
import java.util.*;
@ -29,7 +28,7 @@ public class WorldPie extends AbstractPieChartWithDrilldown {
String[] colors = Theme.getValue(ThemeVal.GRAPH_WORLD_PIE).split(", ");
int colLength = colors.length;
Map<String, Long> playtimePerAlias = AnalysisUtils.getPlaytimePerAlias(worldTimes);
Map<String, Long> playtimePerAlias = worldTimes.getPlaytimePerAlias();
List<String> worlds = new ArrayList<>(playtimePerAlias.keySet());
Collections.sort(worlds);

View File

@ -2,7 +2,7 @@
* License is provided in the jar as LICENSE also here:
* https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/LICENSE
*/
package com.djrapitops.plan.system.webserver.pages.parsing;
package com.djrapitops.plan.utilities.html.pages;
import com.djrapitops.plan.api.exceptions.ParseException;
import com.djrapitops.plan.data.store.containers.AnalysisContainer;

View File

@ -0,0 +1,325 @@
package com.djrapitops.plan.utilities.html.pages;
import com.djrapitops.plan.PlanPlugin;
import com.djrapitops.plan.data.container.Session;
import com.djrapitops.plan.data.store.CachingSupplier;
import com.djrapitops.plan.data.store.Key;
import com.djrapitops.plan.data.store.keys.SessionKeys;
import com.djrapitops.plan.data.store.mutators.formatting.Formatter;
import com.djrapitops.plan.data.store.mutators.formatting.Formatters;
import com.djrapitops.plan.data.store.objects.DateHolder;
import com.djrapitops.plan.system.cache.CacheSystem;
import com.djrapitops.plan.system.cache.SessionCache;
import com.djrapitops.plan.system.database.databases.Database;
import com.djrapitops.plan.system.info.connection.ConnectionLog;
import com.djrapitops.plan.system.info.connection.ConnectionSystem;
import com.djrapitops.plan.system.info.server.Server;
import com.djrapitops.plan.system.info.server.ServerInfo;
import com.djrapitops.plan.system.info.server.properties.ServerProperties;
import com.djrapitops.plan.system.webserver.cache.ResponseCache;
import com.djrapitops.plan.utilities.file.FileUtil;
import com.djrapitops.plan.utilities.html.Html;
import com.djrapitops.plan.utilities.html.HtmlStructure;
import com.djrapitops.plan.utilities.html.icon.Icon;
import com.djrapitops.plan.utilities.html.structure.TabsElement;
import com.djrapitops.plugin.api.Benchmark;
import com.djrapitops.plugin.api.utility.log.ErrorLogger;
import com.djrapitops.plugin.api.utility.log.Log;
import java.io.File;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.nio.charset.Charset;
import java.util.*;
import java.util.function.Supplier;
/**
* Html parsing for the Debug page.
*
* @author Rsl1122
*/
public class DebugPage implements Page {
@Override
public String toHtml() {
StringBuilder preContent = new StringBuilder();
String issueLink = Html.LINK_EXTERNAL.parse("https://github.com/Rsl1122/Plan-PlayerAnalytics/issues/new", "Create new issue on Github");
String hastebinLink = Html.LINK_EXTERNAL.parse("https://hastebin.com/", "Create a new hastebin paste");
preContent.append("<p>")
.append(HtmlStructure.separateWithDots(issueLink, hastebinLink)).append("<br><br>")
.append("This page contains debug information for an issue ticket. You can copy it directly into the issue, the info is pre-formatted.")
.append("</p>");
TabsElement.Tab info = new TabsElement.Tab(Icon.called("server") + " Server Information", createServerInfoContent());
TabsElement.Tab errors = new TabsElement.Tab(Icon.called("exclamation-circle") + " Errors", createErrorContent());
TabsElement.Tab debugLog = new TabsElement.Tab(Icon.called("bug") + " Debug Log", createDebugLogContent());
TabsElement.Tab config = new TabsElement.Tab(Icon.called("cogs") + " Plan Config", createConfigContent());
TabsElement.Tab caches = new TabsElement.Tab(Icon.called("archive") + " Plan Caches", createCacheContent());
TabsElement tabs = new TabsElement(info, errors, debugLog, config, caches);
return preContent + tabs.toHtmlFull();
}
private String createCacheContent() {
StringBuilder content = new StringBuilder();
appendResponseCache(content);
appendSessionCache(content);
appendDataContainerCache(content);
return content.toString();
}
private void appendResponseCache(StringBuilder content) {
try {
content.append("<pre>### Cached Responses:<br><br>");
List<String> cacheKeys = new ArrayList<>(ResponseCache.getCacheKeys());
if (cacheKeys.isEmpty()) {
content.append("Empty");
}
Collections.sort(cacheKeys);
for (String cacheKey : cacheKeys) {
content.append("- ").append(cacheKey).append("<br>");
}
content.append("</pre>");
} catch (Exception e) {
Log.toLog(this.getClass(), e);
}
}
private void appendSessionCache(StringBuilder content) {
try {
content.append("<pre>### Session Cache:<br><br>");
content.append("UUID | Session Started <br>")
.append("-- | -- <br>");
Formatter<Long> timeStamp = Formatters.yearLongValue();
Set<Map.Entry<UUID, Session>> sessions = SessionCache.getActiveSessions().entrySet();
if (sessions.isEmpty()) {
content.append("Empty");
}
for (Map.Entry<UUID, Session> entry : sessions) {
UUID uuid = entry.getKey();
String start = entry.getValue().getValue(SessionKeys.START).map(timeStamp).orElse("Unknown");
content.append(uuid.toString()).append(" | ").append(start).append("<br>");
}
content.append("</pre>");
} catch (Exception e) {
Log.toLog(this.getClass(), e);
}
}
private void appendDataContainerCache(StringBuilder content) {
try {
content.append("<pre>### DataContainer Cache:<br><br>");
content.append("Key | Is Cached | Cache Time <br>")
.append("-- | -- | -- <br>");
Formatter<Long> timeStamp = Formatters.yearLongValue();
Set<Map.Entry<Key, Supplier>> dataContainers = CacheSystem.getInstance().getDataContainerCache().getMap().entrySet();
if (dataContainers.isEmpty()) {
content.append("Empty");
}
for (Map.Entry<Key, Supplier> entry : dataContainers) {
String keyName = entry.getKey().getKeyName();
Supplier supplier = entry.getValue();
if (supplier instanceof CachingSupplier) {
CachingSupplier cachingSupplier = (CachingSupplier) supplier;
boolean isCached = cachingSupplier.isCached();
String cacheText = isCached ? "Yes" : "No";
String cacheTime = isCached ? timeStamp.apply(cachingSupplier.getCacheTime()) : "-";
content.append(keyName).append(" | ").append(cacheText).append(" | ").append(cacheTime).append("<br>");
} else {
content.append(keyName).append(" | ").append("Non-caching Supplier").append(" | ").append("-").append("<br>");
}
}
content.append("</pre>");
} catch (Exception e) {
Log.toLog(this.getClass(), e);
}
}
private String createConfigContent() {
StringBuilder content = new StringBuilder();
appendConfig(content);
return content.toString();
}
private String createDebugLogContent() {
StringBuilder content = new StringBuilder();
appendDebugLog(content);
return content.toString();
}
private String createErrorContent() {
StringBuilder content = new StringBuilder();
appendLoggedErrors(content);
return content.toString();
}
private String createServerInfoContent() {
StringBuilder content = new StringBuilder();
appendServerInformation(content);
appendConnectionLog(content);
appendBenchmarks(content);
return content.toString();
}
private void appendConnectionLog(StringBuilder content) {
try {
Map<String, Map<String, ConnectionLog.Entry>> logEntries = ConnectionLog.getLogEntries();
content.append("<pre>### Connection Log:<br><br>");
content.append("Server Address | Request Type | Response | Sent<br>")
.append("-- | -- | -- | --<br>");
Formatter<DateHolder> formatter = Formatters.second();
if (logEntries.isEmpty()) {
content.append("**No Connections Logged**<br>");
}
for (Map.Entry<String, Map<String, ConnectionLog.Entry>> entry : logEntries.entrySet()) {
String address = entry.getKey();
Map<String, ConnectionLog.Entry> requests = entry.getValue();
for (Map.Entry<String, ConnectionLog.Entry> requestEntry : requests.entrySet()) {
String infoRequest = requestEntry.getKey();
ConnectionLog.Entry logEntry = requestEntry.getValue();
content.append(address).append(" | ")
.append(infoRequest).append(" | ")
.append(logEntry.getResponseCode()).append(" | ")
.append(formatter.apply(logEntry)).append("<br>");
}
}
content.append("</pre>");
content.append("<pre>### Servers:<br><br>");
List<Server> servers = ConnectionSystem.getInstance().getBukkitServers();
content.append("Server Name | Address | UUID <br>")
.append("-- | -- | --<br>");
for (Server server : servers) {
content.append(server.getName()).append(" | ")
.append(server.getWebAddress()).append(" | ")
.append(server.getUuid()).append("<br>");
}
content.append("</pre>");
} catch (Exception e) {
Log.toLog(this.getClass(), e);
}
}
private void appendServerInformation(StringBuilder content) {
PlanPlugin plugin = PlanPlugin.getInstance();
ServerProperties variable = ServerInfo.getServerProperties();
content.append("<pre>### Server Information<br>")
.append("**Plan Version:** ").append(plugin.getVersion()).append("<br>");
content.append("**Server:** ");
content.append(variable.getName())
.append(" ").append(variable.getImplVersion())
.append(" ").append(variable.getVersion());
content.append("<br>");
Database database = Database.getActive();
content.append("**Database:** ").append(database.getName());
content.append("<br><br>");
RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
Properties properties = System.getProperties();
String osName = properties.getProperty("os.name");
String osVersion = properties.getProperty("os.version");
String osArch = properties.getProperty("os.arch");
String javaVendor = properties.getProperty("java.vendor");
String javaVersion = properties.getProperty("java.version");
String javaVMVendor = properties.getProperty("java.vm.vendor");
String javaVMName = properties.getProperty("java.vm.name");
String javaVMVersion = properties.getProperty("java.vm.version");
List<String> javaVMFlags = runtimeMxBean.getInputArguments();
content.append("**Operating SubSystem:** ").append(osName).append(" (").append(osArch)
.append(") version ").append(osVersion).append("<br>");
content.append("**Java Version:** ").append(javaVersion).append(", ").append(javaVendor).append("<br>");
content.append("**Java VM Version:** ").append(javaVMName).append(" version ").append(javaVMVersion)
.append(", ").append(javaVMVendor).append("<br>");
content.append("**Java VM Flags:** ").append(javaVMFlags).append("<br>");
content.append("</pre>");
}
private void appendConfig(StringBuilder content) {
try {
File configFile = new File(PlanPlugin.getInstance().getDataFolder(), "config.yml");
if (configFile.exists()) {
content.append("<pre>### config.yml<br>&#96;&#96;&#96;<br>");
FileUtil.lines(configFile, Charset.forName("UTF-8"))
.stream().filter(line -> !line.toLowerCase().contains("pass") && !line.toLowerCase().contains("secret"))
.forEach(line -> content.append(line).append("<br>"));
content.append("&#96;&#96;&#96;</pre>");
}
} catch (IOException e) {
Log.toLog(this.getClass(), e);
}
}
private void appendBenchmarks(StringBuilder content) {
content.append("<pre>### Benchmarks<br>&#96;&#96;&#96;<br>");
try {
for (String line : Benchmark.getAverages().asStringArray()) {
content.append(line).append("<br>");
}
} catch (Exception e) {
content.append("Exception on Benchmark.getAverages().asStringArray()");
}
content.append("&#96;&#96;&#96;</pre>");
}
private void appendLoggedErrors(StringBuilder content) {
try {
content.append("<pre>### Logged Errors<br>");
SortedMap<String, List<String>> errors = ErrorLogger.getLoggedErrors(PlanPlugin.getInstance());
if (!errors.isEmpty()) {
List<String> errorLines = new ArrayList<>();
for (Map.Entry<String, List<String>> entry : errors.entrySet()) {
StringBuilder errorLineBuilder = new StringBuilder();
for (String line : entry.getValue()) {
errorLineBuilder.append(line).append("<br>");
}
String error = errorLineBuilder.toString();
if (!errorLines.contains(error)) {
errorLines.add(error);
}
}
for (String error : errorLines) {
content.append("</pre><pre>&#96;&#96;&#96;<br>")
.append(error)
.append("&#96;&#96;&#96;");
}
} else {
content.append("**No Errors logged.**<br>");
}
content.append("</pre>");
} catch (IOException e) {
Log.toLog(this.getClass(), e);
}
}
private void appendDebugLog(StringBuilder content) {
content.append("<pre>### Debug Log<br>&#96;&#96;&#96;<br>");
for (String line : Log.getDebugLogInMemory()) {
content.append(line).append("<br>");
}
content.append("&#96;&#96;&#96;</pre>");
}
}

View File

@ -2,7 +2,7 @@
* License is provided in the jar as LICENSE also here:
* https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/LICENSE
*/
package com.djrapitops.plan.system.webserver.pages.parsing;
package com.djrapitops.plan.utilities.html.pages;
import com.djrapitops.plan.api.exceptions.ParseException;
import com.djrapitops.plan.data.container.Session;

View File

@ -2,13 +2,15 @@
* License is provided in the jar as LICENSE also here:
* https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/LICENSE
*/
package com.djrapitops.plan.system.webserver.pages.parsing;
package com.djrapitops.plan.utilities.html.pages;
import com.djrapitops.plan.api.exceptions.ParseException;
import com.djrapitops.plan.data.store.containers.NetworkContainer;
import com.djrapitops.plan.data.store.keys.NetworkKeys;
import com.djrapitops.plan.data.store.mutators.formatting.PlaceholderReplacer;
import com.djrapitops.plan.system.webserver.response.cache.PageId;
import com.djrapitops.plan.system.webserver.response.cache.ResponseCache;
import com.djrapitops.plan.system.info.server.ServerInfo;
import com.djrapitops.plan.system.webserver.cache.PageId;
import com.djrapitops.plan.system.webserver.cache.ResponseCache;
import com.djrapitops.plan.system.webserver.response.pages.parts.NetworkPageContent;
import com.djrapitops.plan.utilities.file.FileUtil;
@ -30,6 +32,8 @@ public class NetworkPage implements Page {
@Override
public String toHtml() throws ParseException {
try {
networkContainer.putSupplier(NetworkKeys.PLAYERS_ONLINE, ServerInfo.getServerProperties()::getOnlinePlayers);
PlaceholderReplacer placeholderReplacer = new PlaceholderReplacer();
placeholderReplacer.addAllPlaceholdersFrom(networkContainer,
VERSION, NETWORK_NAME, TIME_ZONE,

View File

@ -2,7 +2,7 @@
* License is provided in the jar as LICENSE also here:
* https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/LICENSE
*/
package com.djrapitops.plan.system.webserver.pages.parsing;
package com.djrapitops.plan.utilities.html.pages;
import com.djrapitops.plan.api.exceptions.ParseException;

View File

@ -1,4 +1,4 @@
package com.djrapitops.plan.system.webserver.pages.parsing;
package com.djrapitops.plan.utilities.html.pages;
import com.djrapitops.plan.PlanPlugin;
import com.djrapitops.plan.api.exceptions.ParseException;

View File

@ -10,7 +10,6 @@ import com.djrapitops.plan.data.time.WorldTimes;
import com.djrapitops.plan.system.settings.Settings;
import com.djrapitops.plan.system.settings.theme.Theme;
import com.djrapitops.plan.system.settings.theme.ThemeVal;
import com.djrapitops.plan.utilities.analysis.AnalysisUtils;
import com.djrapitops.plan.utilities.comparators.DateHolderRecentComparator;
import com.djrapitops.plan.utilities.html.HtmlStructure;
import com.djrapitops.plan.utilities.html.graphs.pie.WorldPie;
@ -98,6 +97,7 @@ public class SessionAccordion extends AbstractAccordion {
WorldTimes worldTimes = session.getValue(SessionKeys.WORLD_TIMES).orElse(new WorldTimes(new HashMap<>()));
WorldPie worldPie = new WorldPie(worldTimes);
String longestWorldPlayed = session.getValue(SessionKeys.LONGEST_WORLD_PLAYED).orElse("Unknown");
boolean hasEnded = session.supports(SessionKeys.END);
String sessionEnd = hasEnded ? timeStampFormatter.apply(() -> session.getUnsafe(SessionKeys.END)) : "Online";
@ -110,7 +110,7 @@ public class SessionAccordion extends AbstractAccordion {
int deaths = session.getValue(SessionKeys.DEATH_COUNT).orElse(0);
String info = appendWorldPercentage
? HtmlStructure.separateWithDots(sessionStart, AnalysisUtils.getLongestWorldPlayed(session))
? HtmlStructure.separateWithDots(sessionStart, longestWorldPlayed)
: sessionStart;
String title = HtmlStructure.separateWithDots(playerName, info) + "<span class=\"pull-right\">" + length + "</span>";
String htmlID = "" + session.getValue(SessionKeys.START).orElse(0L) + i;
@ -170,6 +170,7 @@ public class SessionAccordion extends AbstractAccordion {
WorldTimes worldTimes = session.getValue(SessionKeys.WORLD_TIMES).orElse(new WorldTimes(new HashMap<>()));
WorldPie worldPie = new WorldPie(worldTimes);
String longestWorldPlayed = session.getValue(SessionKeys.LONGEST_WORLD_PLAYED).orElse("Unknown");
boolean hasEnded = session.supports(SessionKeys.END);
String sessionEnd = hasEnded ? timeStampFormatter.apply(() -> session.getValue(SessionKeys.END).orElse(0L)) : "Online";
@ -182,7 +183,7 @@ public class SessionAccordion extends AbstractAccordion {
int deaths = session.getValue(SessionKeys.DEATH_COUNT).orElse(0);
String info = appendWorldPercentage
? HtmlStructure.separateWithDots(sessionStart, AnalysisUtils.getLongestWorldPlayed(session))
? HtmlStructure.separateWithDots(sessionStart, longestWorldPlayed)
: sessionStart;
String title = HtmlStructure.separateWithDots(serverName, info) + "<span class=\"pull-right\">" + length + "</span>";
String htmlID = "" + session.getValue(SessionKeys.START).orElse(0L) + i;

View File

@ -8,7 +8,6 @@ import com.djrapitops.plan.data.store.keys.PlayerKeys;
import com.djrapitops.plan.data.store.keys.SessionKeys;
import com.djrapitops.plan.data.store.mutators.formatting.Formatters;
import com.djrapitops.plan.system.settings.Settings;
import com.djrapitops.plan.utilities.analysis.AnalysisUtils;
import com.djrapitops.plan.utilities.html.Html;
import java.util.ArrayList;
@ -57,7 +56,7 @@ public class PlayerSessionTable extends TableContainer {
String length = session.supports(SessionKeys.END)
? Formatters.timeAmount().apply(session.getValue(SessionKeys.LENGTH).orElse(0L))
: "Online";
String world = AnalysisUtils.getLongestWorldPlayed(session);
String world = session.getValue(SessionKeys.LONGEST_WORLD_PLAYED).orElse("Unknown");
String toolTip = "Session ID: " + session.getValue(SessionKeys.DB_ID)
.map(id -> Integer.toString(id))

View File

@ -6,7 +6,6 @@ import com.djrapitops.plan.data.element.TableContainer;
import com.djrapitops.plan.data.store.keys.SessionKeys;
import com.djrapitops.plan.data.store.mutators.formatting.Formatters;
import com.djrapitops.plan.system.settings.Settings;
import com.djrapitops.plan.utilities.analysis.AnalysisUtils;
import com.djrapitops.plan.utilities.html.Html;
import java.util.List;
@ -47,7 +46,7 @@ public class ServerSessionTable extends TableContainer {
String length = session.supports(SessionKeys.END)
? Formatters.timeAmount().apply(session.getValue(SessionKeys.LENGTH).orElse(0L))
: "Online";
String world = AnalysisUtils.getLongestWorldPlayed(session);
String world = session.getValue(SessionKeys.LONGEST_WORLD_PLAYED).orElse("Unknown");
String toolTip = "Session ID: " + session.getValue(SessionKeys.DB_ID)
.map(id -> Integer.toString(id))

View File

@ -58,9 +58,7 @@ public class UUIDUtility {
try {
uuid = db.fetch().getUuidOf(playerName);
} catch (DBOpException e) {
if (e.isFatal()) {
Log.toLog(UUIDUtility.class, e);
}
Log.toLog(UUIDUtility.class, e);
}
try {
if (uuid == null) {

View File

@ -1,7 +1,7 @@
package com.djrapitops.plan.data.cache;
import com.djrapitops.plan.system.webserver.cache.ResponseCache;
import com.djrapitops.plan.system.webserver.response.Response;
import com.djrapitops.plan.system.webserver.response.cache.ResponseCache;
import org.junit.Test;
import utilities.RandomData;