mirror of
https://github.com/plan-player-analytics/Plan.git
synced 2024-12-21 05:50:18 +08:00
Optimized (memory) /server players table query
This commit is contained in:
parent
54f98c9fab
commit
2412f5b9d5
@ -0,0 +1,182 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.delivery.domain;
|
||||
|
||||
import com.djrapitops.plan.delivery.domain.mutators.ActivityIndex;
|
||||
import com.djrapitops.plan.gathering.domain.BaseUser;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Represents a player displayed on a player table on players tab or /players page.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class TablePlayer implements Comparable<TablePlayer> {
|
||||
|
||||
private UUID uuid;
|
||||
private String name;
|
||||
private ActivityIndex activityIndex;
|
||||
private Long playtime;
|
||||
private Integer sessionCount;
|
||||
private Long registered;
|
||||
private Long lastSeen;
|
||||
private String geolocation;
|
||||
|
||||
private boolean banned = false;
|
||||
|
||||
private TablePlayer() {
|
||||
}
|
||||
|
||||
public static TablePlayer.Builder builder() {
|
||||
return new TablePlayer.Builder();
|
||||
}
|
||||
|
||||
public static TablePlayer.Builder builderFromBaseUser(BaseUser baseUser) {
|
||||
return new TablePlayer.Builder()
|
||||
.uuid(baseUser.getUuid())
|
||||
.name(baseUser.getName())
|
||||
.registered(baseUser.getRegistered());
|
||||
}
|
||||
|
||||
public UUID getPlayerUUID() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public Optional<String> getName() {
|
||||
return Optional.ofNullable(name);
|
||||
}
|
||||
|
||||
public Optional<ActivityIndex> getCurrentActivityIndex() {
|
||||
return Optional.ofNullable(activityIndex);
|
||||
}
|
||||
|
||||
public Optional<Long> getPlaytime() {
|
||||
return Optional.ofNullable(playtime);
|
||||
}
|
||||
|
||||
public Optional<Integer> getSessionCount() {
|
||||
return Optional.ofNullable(sessionCount);
|
||||
}
|
||||
|
||||
public Optional<Long> getRegistered() {
|
||||
return Optional.ofNullable(registered);
|
||||
}
|
||||
|
||||
public Optional<Long> getLastSeen() {
|
||||
return Optional.ofNullable(lastSeen);
|
||||
}
|
||||
|
||||
public Optional<String> getGeolocation() {
|
||||
return Optional.ofNullable(geolocation);
|
||||
}
|
||||
|
||||
public boolean isBanned() {
|
||||
return banned;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(TablePlayer other) {
|
||||
// Most recent first
|
||||
return Long.compare(
|
||||
other.lastSeen != null ? other.lastSeen : 0L,
|
||||
this.lastSeen != null ? this.lastSeen : 0L
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof TablePlayer)) return false;
|
||||
TablePlayer that = (TablePlayer) o;
|
||||
return playtime == that.playtime &&
|
||||
sessionCount == that.sessionCount &&
|
||||
registered == that.registered &&
|
||||
lastSeen == that.lastSeen &&
|
||||
name.equals(that.name) &&
|
||||
activityIndex.equals(that.activityIndex) &&
|
||||
geolocation.equals(that.geolocation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(name, activityIndex, playtime, sessionCount, registered, lastSeen, geolocation);
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private final TablePlayer player;
|
||||
|
||||
public Builder() {
|
||||
player = new TablePlayer();
|
||||
}
|
||||
|
||||
public UUID getPlayerUUID() {
|
||||
return player.uuid;
|
||||
}
|
||||
|
||||
public Builder uuid(UUID playerUUID) {
|
||||
player.uuid = playerUUID;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder name(String name) {
|
||||
player.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder banned() {
|
||||
player.banned = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder activityIndex(ActivityIndex activityIndex) {
|
||||
player.activityIndex = activityIndex;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder playtime(long playtime) {
|
||||
player.playtime = playtime;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder sessionCount(int count) {
|
||||
player.sessionCount = count;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder registered(long registered) {
|
||||
player.registered = registered;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder lastSeen(long lastSeen) {
|
||||
player.lastSeen = lastSeen;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder geolocation(String geolocation) {
|
||||
player.geolocation = geolocation;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TablePlayer build() {
|
||||
return player;
|
||||
}
|
||||
}
|
||||
}
|
@ -37,8 +37,6 @@ import com.djrapitops.plan.settings.config.paths.TimeSettings;
|
||||
import com.djrapitops.plan.storage.database.DBSystem;
|
||||
import com.djrapitops.plan.storage.database.Database;
|
||||
import com.djrapitops.plan.storage.database.queries.analysis.PlayerCountQueries;
|
||||
import com.djrapitops.plan.storage.database.queries.containers.AllPlayerContainersQuery;
|
||||
import com.djrapitops.plan.storage.database.queries.containers.ServerPlayersTableContainersQuery;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.*;
|
||||
import com.djrapitops.plan.utilities.comparators.SessionStartComparator;
|
||||
|
||||
@ -84,9 +82,9 @@ public class JSONFactory {
|
||||
Database database = dbSystem.getDatabase();
|
||||
|
||||
return new PlayersTableJSONParser(
|
||||
database.query(new ServerPlayersTableContainersQuery(serverUUID)),
|
||||
database.query(new ServerTablePlayersQuery(serverUUID, System.currentTimeMillis(), playtimeThreshold, xMostRecentPlayers)),
|
||||
database.query(new ExtensionServerPlayerDataTableQuery(serverUUID, xMostRecentPlayers)),
|
||||
xMostRecentPlayers, playtimeThreshold, openPlayerLinksInNewTab,
|
||||
openPlayerLinksInNewTab,
|
||||
formatters
|
||||
).toJSONString();
|
||||
}
|
||||
@ -99,9 +97,9 @@ public class JSONFactory {
|
||||
Database database = dbSystem.getDatabase();
|
||||
|
||||
return new PlayersTableJSONParser(
|
||||
database.query(new AllPlayerContainersQuery()), // TODO Optimize the heck out of this
|
||||
Collections.emptyList(),// TODO Replace with new query
|
||||
Collections.emptyMap(),
|
||||
xMostRecentPlayers, playtimeThreshold, openPlayerLinksInNewTab,
|
||||
openPlayerLinksInNewTab,
|
||||
formatters
|
||||
).toJSONString();
|
||||
}
|
||||
|
@ -16,11 +16,8 @@
|
||||
*/
|
||||
package com.djrapitops.plan.delivery.rendering.json;
|
||||
|
||||
import com.djrapitops.plan.delivery.domain.container.PlayerContainer;
|
||||
import com.djrapitops.plan.delivery.domain.keys.PlayerKeys;
|
||||
import com.djrapitops.plan.delivery.domain.TablePlayer;
|
||||
import com.djrapitops.plan.delivery.domain.mutators.ActivityIndex;
|
||||
import com.djrapitops.plan.delivery.domain.mutators.GeoInfoMutator;
|
||||
import com.djrapitops.plan.delivery.domain.mutators.SessionsMutator;
|
||||
import com.djrapitops.plan.delivery.formatting.Formatter;
|
||||
import com.djrapitops.plan.delivery.formatting.Formatters;
|
||||
import com.djrapitops.plan.delivery.rendering.html.Html;
|
||||
@ -29,8 +26,6 @@ import com.djrapitops.plan.delivery.rendering.html.icon.Icon;
|
||||
import com.djrapitops.plan.extension.FormatType;
|
||||
import com.djrapitops.plan.extension.icon.Color;
|
||||
import com.djrapitops.plan.extension.implementation.results.*;
|
||||
import com.djrapitops.plan.gathering.domain.GeoInfo;
|
||||
import com.djrapitops.plan.utilities.comparators.PlayerContainerLastPlayedComparator;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@ -43,12 +38,10 @@ import java.util.*;
|
||||
*/
|
||||
public class PlayersTableJSONParser {
|
||||
|
||||
private final List<PlayerContainer> players;
|
||||
private final List<TablePlayer> players;
|
||||
private final List<ExtensionDescriptive> extensionDescriptives;
|
||||
private final Map<UUID, ExtensionTabData> extensionData;
|
||||
|
||||
private final int maxPlayers;
|
||||
private final long activeMsThreshold;
|
||||
private final boolean openPlayerPageInNewTab;
|
||||
|
||||
private Map<FormatType, Formatter<Long>> numberFormatters;
|
||||
@ -57,10 +50,10 @@ public class PlayersTableJSONParser {
|
||||
|
||||
public PlayersTableJSONParser(
|
||||
// Data
|
||||
List<PlayerContainer> players,
|
||||
List<TablePlayer> players,
|
||||
Map<UUID, ExtensionTabData> extensionData,
|
||||
// Settings
|
||||
int maxPlayers, long activeMsThreshold, boolean openPlayerPageInNewTab,
|
||||
boolean openPlayerPageInNewTab,
|
||||
// Formatters
|
||||
Formatters formatters
|
||||
) {
|
||||
@ -73,8 +66,6 @@ public class PlayersTableJSONParser {
|
||||
extensionDescriptives.sort((one, two) -> String.CASE_INSENSITIVE_ORDER.compare(one.getName(), two.getName()));
|
||||
|
||||
// Settings
|
||||
this.maxPlayers = maxPlayers;
|
||||
this.activeMsThreshold = activeMsThreshold;
|
||||
this.openPlayerPageInNewTab = openPlayerPageInNewTab;
|
||||
// Formatters
|
||||
numberFormatters = new EnumMap<>(FormatType.class);
|
||||
@ -107,15 +98,9 @@ public class PlayersTableJSONParser {
|
||||
private String parseData() {
|
||||
StringBuilder dataJSON = new StringBuilder("[");
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
players.sort(new PlayerContainerLastPlayedComparator());
|
||||
|
||||
int currentPlayerNumber = 0;
|
||||
for (PlayerContainer player : players) {
|
||||
if (currentPlayerNumber >= maxPlayers) {
|
||||
break;
|
||||
}
|
||||
UUID playerUUID = player.getValue(PlayerKeys.UUID).orElse(null);
|
||||
for (TablePlayer player : players) {
|
||||
UUID playerUUID = player.getPlayerUUID();
|
||||
if (playerUUID == null) {
|
||||
continue;
|
||||
}
|
||||
@ -125,7 +110,7 @@ public class PlayersTableJSONParser {
|
||||
}
|
||||
dataJSON.append('{'); // Start new item
|
||||
|
||||
appendPlayerData(dataJSON, now, player);
|
||||
appendPlayerData(dataJSON, player);
|
||||
appendExtensionData(dataJSON, extensionData.getOrDefault(playerUUID, new ExtensionTabData.Factory(null).build()));
|
||||
|
||||
dataJSON.append('}'); // Close new item
|
||||
@ -135,22 +120,21 @@ public class PlayersTableJSONParser {
|
||||
return dataJSON.append(']').toString();
|
||||
}
|
||||
|
||||
private void appendPlayerData(StringBuilder dataJSON, long now, PlayerContainer player) {
|
||||
String name = player.getValue(PlayerKeys.NAME).orElse("Unknown");
|
||||
private void appendPlayerData(StringBuilder dataJSON, TablePlayer player) {
|
||||
String name = player.getName().orElse(player.getPlayerUUID().toString());
|
||||
String url = "../player/" + name;
|
||||
|
||||
SessionsMutator sessionsMutator = SessionsMutator.forContainer(player);
|
||||
int loginTimes = sessionsMutator.count();
|
||||
long playtime = sessionsMutator.toPlaytime();
|
||||
long registered = player.getValue(PlayerKeys.REGISTERED).orElse(0L);
|
||||
long lastSeen = sessionsMutator.toLastSeen();
|
||||
int loginTimes = player.getSessionCount().orElse(0);
|
||||
long playtime = player.getPlaytime().orElse(-1L);
|
||||
long registered = player.getRegistered().orElse(-1L);
|
||||
long lastSeen = player.getLastSeen().orElse(-1L);
|
||||
|
||||
ActivityIndex activityIndex = player.getActivityIndex(now, activeMsThreshold);
|
||||
boolean isBanned = player.getValue(PlayerKeys.BANNED).orElse(false);
|
||||
ActivityIndex activityIndex = player.getCurrentActivityIndex().orElseGet(() -> new ActivityIndex(0.0, 0));
|
||||
boolean isBanned = player.isBanned();
|
||||
String activityString = activityIndex.getFormattedValue(decimalFormatter)
|
||||
+ (isBanned ? " (<b>Banned</b>)" : " (" + activityIndex.getGroup() + ")");
|
||||
|
||||
String geolocation = GeoInfoMutator.forContainer(player).mostRecent().map(GeoInfo::getGeolocation).orElse("-");
|
||||
String geolocation = player.getGeolocation().orElse("-");
|
||||
|
||||
Html link = openPlayerPageInNewTab ? Html.LINK_EXTERNAL : Html.LINK;
|
||||
|
||||
|
@ -112,7 +112,7 @@ public class WorldAliasSettings {
|
||||
String worldName = entry.getKey();
|
||||
long playtime = entry.getValue();
|
||||
|
||||
if (!aliases.contains(worldName)) {
|
||||
if (worldName != null && !aliases.contains(worldName)) {
|
||||
addWorld(worldName);
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@ import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import static com.djrapitops.plan.storage.database.sql.parsing.Sql.*;
|
||||
|
||||
@ -72,7 +73,7 @@ public class ActivityIndexQueries {
|
||||
return fetchActivityGroupCount(date, serverUUID, playtimeThreshold, ActivityIndex.REGULAR, 5.1);
|
||||
}
|
||||
|
||||
private static String selectActivityIndexSQL() {
|
||||
public static String selectActivityIndexSQL() {
|
||||
String selectActivePlaytimeSQL = SELECT +
|
||||
SessionsTable.USER_UUID +
|
||||
",SUM(" +
|
||||
@ -93,7 +94,7 @@ public class ActivityIndexQueries {
|
||||
GROUP_BY + "q1." + SessionsTable.USER_UUID;
|
||||
}
|
||||
|
||||
private static void setSelectActivityIndexSQLParameters(PreparedStatement statement, int index, long playtimeThreshold, UUID serverUUID, long date) throws SQLException {
|
||||
public static void setSelectActivityIndexSQLParameters(PreparedStatement statement, int index, long playtimeThreshold, UUID serverUUID, long date) throws SQLException {
|
||||
statement.setDouble(index, Math.PI);
|
||||
statement.setLong(index + 1, playtimeThreshold);
|
||||
|
||||
@ -477,4 +478,28 @@ public class ActivityIndexQueries {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Query<Object> activityIndexOnServerToMap(UUID serverUUID, long date, long threshold, BiConsumer<UUID, Double> consumer) {
|
||||
String sql = SELECT + "activity_index,n." + UserInfoTable.USER_UUID +
|
||||
FROM + UserInfoTable.TABLE_NAME + " n" +
|
||||
LEFT_JOIN + '(' + selectActivityIndexSQL() + ") a on n." + SessionsTable.USER_UUID + "=a." + UserInfoTable.USER_UUID +
|
||||
WHERE + UserInfoTable.SERVER_UUID + "=?";
|
||||
|
||||
return new QueryStatement<Object>(sql, 1000) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
setSelectActivityIndexSQLParameters(statement, 1, threshold, serverUUID, date);
|
||||
statement.setString(2, serverUUID.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object processResults(ResultSet set) throws SQLException {
|
||||
while (set.next()) {
|
||||
double activityIndex = set.getDouble("activity_index"); // Returns 0.0 if missing
|
||||
consumer.accept(UUID.fromString(set.getString(UserInfoTable.USER_UUID)), activityIndex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.storage.database.queries.containers;
|
||||
|
||||
import com.djrapitops.plan.delivery.domain.container.PlayerContainer;
|
||||
import com.djrapitops.plan.delivery.domain.keys.PlayerKeys;
|
||||
import com.djrapitops.plan.delivery.domain.mutators.SessionsMutator;
|
||||
import com.djrapitops.plan.gathering.domain.BaseUser;
|
||||
import com.djrapitops.plan.gathering.domain.GeoInfo;
|
||||
import com.djrapitops.plan.gathering.domain.Session;
|
||||
import com.djrapitops.plan.storage.database.SQLDB;
|
||||
import com.djrapitops.plan.storage.database.queries.Query;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.BaseUserQueries;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.GeoInfoQueries;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.SessionQueries;
|
||||
import com.djrapitops.plan.storage.database.queries.objects.UserInfoQueries;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Optimized version of {@link ServerPlayerContainersQuery} for /server page Players table.
|
||||
*
|
||||
* @author Rsl1122
|
||||
* @see com.djrapitops.plan.delivery.rendering.json.PlayersTableJSONParser For what needs to be included.
|
||||
*/
|
||||
public class ServerPlayersTableContainersQuery implements Query<List<PlayerContainer>> {
|
||||
|
||||
private final UUID serverUUID;
|
||||
|
||||
public ServerPlayersTableContainersQuery(UUID serverUUID) {
|
||||
this.serverUUID = serverUUID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PlayerContainer> executeQuery(SQLDB db) {
|
||||
List<PlayerContainer> containers = new ArrayList<>();
|
||||
|
||||
Collection<BaseUser> baseUsers = db.query(BaseUserQueries.fetchServerBaseUsers(serverUUID));
|
||||
|
||||
Map<UUID, List<GeoInfo>> geoInformation = db.query(GeoInfoQueries.fetchServerGeoInformation(serverUUID));
|
||||
// TODO Optimize the heck out of this
|
||||
Map<UUID, List<Session>> sessions = db.query(SessionQueries.fetchSessionsOfServer(serverUUID));
|
||||
Set<UUID> bannedUsers = db.query(UserInfoQueries.fetchBannedUUIDsOfServer(serverUUID));
|
||||
|
||||
for (BaseUser user : baseUsers) {
|
||||
PlayerContainer container = new PlayerContainer();
|
||||
|
||||
// BaseUser
|
||||
UUID uuid = user.getUuid();
|
||||
container.putRawData(PlayerKeys.UUID, uuid);
|
||||
container.putRawData(PlayerKeys.NAME, user.getName());
|
||||
container.putRawData(PlayerKeys.REGISTERED, user.getRegistered());
|
||||
container.putRawData(PlayerKeys.BANNED, bannedUsers.contains(uuid));
|
||||
|
||||
// GeoInfo
|
||||
container.putRawData(PlayerKeys.GEO_INFO, geoInformation.getOrDefault(uuid, new ArrayList<>()));
|
||||
|
||||
container.putCachingSupplier(PlayerKeys.SESSIONS, () -> {
|
||||
List<Session> playerSessions = sessions.getOrDefault(uuid, new ArrayList<>());
|
||||
container.getValue(PlayerKeys.ACTIVE_SESSION).ifPresent(playerSessions::add);
|
||||
return playerSessions;
|
||||
}
|
||||
);
|
||||
container.putCachingSupplier(PlayerKeys.LAST_SEEN, () -> SessionsMutator.forContainer(container).toLastSeen());
|
||||
|
||||
containers.add(container);
|
||||
}
|
||||
return containers;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.djrapitops.plan.storage.database.queries.objects;
|
||||
|
||||
import com.djrapitops.plan.delivery.domain.TablePlayer;
|
||||
import com.djrapitops.plan.delivery.domain.mutators.ActivityIndex;
|
||||
import com.djrapitops.plan.storage.database.SQLDB;
|
||||
import com.djrapitops.plan.storage.database.queries.Query;
|
||||
import com.djrapitops.plan.storage.database.queries.QueryStatement;
|
||||
import com.djrapitops.plan.storage.database.queries.analysis.ActivityIndexQueries;
|
||||
import com.djrapitops.plan.storage.database.sql.tables.GeoInfoTable;
|
||||
import com.djrapitops.plan.storage.database.sql.tables.SessionsTable;
|
||||
import com.djrapitops.plan.storage.database.sql.tables.UserInfoTable;
|
||||
import com.djrapitops.plan.storage.database.sql.tables.UsersTable;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.djrapitops.plan.storage.database.sql.parsing.Sql.*;
|
||||
|
||||
/**
|
||||
* Query for displaying players on /server page players tab.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class ServerTablePlayersQuery implements Query<List<TablePlayer>> {
|
||||
|
||||
private final UUID serverUUID;
|
||||
private final long date;
|
||||
private final long activeMsThreshold;
|
||||
private final int xMostRecentPlayers;
|
||||
|
||||
public ServerTablePlayersQuery(UUID serverUUID, long date, long activeMsThreshold, int xMostRecentPlayers) {
|
||||
this.serverUUID = serverUUID;
|
||||
this.date = date;
|
||||
this.activeMsThreshold = activeMsThreshold;
|
||||
this.xMostRecentPlayers = xMostRecentPlayers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TablePlayer> executeQuery(SQLDB db) {
|
||||
String selectGeolocations = SELECT +
|
||||
GeoInfoTable.USER_UUID + ", " +
|
||||
GeoInfoTable.GEOLOCATION + ", " +
|
||||
GeoInfoTable.LAST_USED +
|
||||
FROM + GeoInfoTable.TABLE_NAME;
|
||||
String selectLatestGeolocationDate = SELECT +
|
||||
GeoInfoTable.USER_UUID + ", " +
|
||||
"MAX(" + GeoInfoTable.LAST_USED + ") as last_used_g" +
|
||||
FROM + GeoInfoTable.TABLE_NAME +
|
||||
GROUP_BY + GeoInfoTable.USER_UUID;
|
||||
String selectLatestGeolocations = SELECT +
|
||||
"g1." + GeoInfoTable.GEOLOCATION + ',' +
|
||||
"g1." + GeoInfoTable.USER_UUID +
|
||||
FROM + "(" + selectGeolocations + ") AS g1" +
|
||||
INNER_JOIN + "(" + selectLatestGeolocationDate + ") AS g2 ON g1.uuid = g2.uuid" +
|
||||
WHERE + GeoInfoTable.LAST_USED + "=last_used_g";
|
||||
|
||||
String selectSessionData = SELECT + "s." + SessionsTable.USER_UUID + ',' +
|
||||
"MAX(" + SessionsTable.SESSION_END + ") as last_seen," +
|
||||
"COUNT(1) as count," +
|
||||
"SUM(" + SessionsTable.SESSION_END + '-' + SessionsTable.SESSION_START + ") as playtime" +
|
||||
FROM + SessionsTable.TABLE_NAME + " s" +
|
||||
WHERE + "s." + SessionsTable.SERVER_UUID + "=?" +
|
||||
GROUP_BY + "s." + SessionsTable.USER_UUID;
|
||||
|
||||
String selectBaseUsers = SELECT +
|
||||
"u." + UsersTable.USER_UUID + ',' +
|
||||
"u." + UsersTable.USER_NAME + ',' +
|
||||
"u." + UsersTable.REGISTERED + ',' +
|
||||
UserInfoTable.BANNED + ',' +
|
||||
"geoloc." + GeoInfoTable.GEOLOCATION + ',' +
|
||||
"ses.last_seen," +
|
||||
"ses.count," +
|
||||
"ses.playtime," +
|
||||
"act.activity_index" +
|
||||
FROM + UsersTable.TABLE_NAME + " u" +
|
||||
INNER_JOIN + UserInfoTable.TABLE_NAME + " on u." + UsersTable.USER_UUID + "=" + UserInfoTable.TABLE_NAME + '.' + UserInfoTable.USER_UUID +
|
||||
LEFT_JOIN + '(' + selectLatestGeolocations + ") geoloc on geoloc." + GeoInfoTable.USER_UUID + "=u." + UsersTable.USER_UUID +
|
||||
LEFT_JOIN + '(' + selectSessionData + ") ses on ses." + SessionsTable.USER_UUID + "=u." + UsersTable.USER_UUID +
|
||||
LEFT_JOIN + '(' + ActivityIndexQueries.selectActivityIndexSQL() + ") act on u." + SessionsTable.USER_UUID + "=act." + UserInfoTable.USER_UUID +
|
||||
WHERE + UserInfoTable.SERVER_UUID + "=?" +
|
||||
ORDER_BY + "ses.last_seen DESC LIMIT ?";
|
||||
|
||||
return db.query(new QueryStatement<List<TablePlayer>>(selectBaseUsers, 1000) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, serverUUID.toString()); // Session query
|
||||
ActivityIndexQueries.setSelectActivityIndexSQLParameters(statement, 2, activeMsThreshold, serverUUID, date);
|
||||
statement.setString(13, serverUUID.toString()); // Session query
|
||||
statement.setInt(14, xMostRecentPlayers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TablePlayer> processResults(ResultSet set) throws SQLException {
|
||||
List<TablePlayer> players = new ArrayList<>();
|
||||
while (set.next()) {
|
||||
TablePlayer.Builder player = TablePlayer.builder()
|
||||
.uuid(UUID.fromString(set.getString(UsersTable.USER_UUID)))
|
||||
.name(set.getString(UsersTable.USER_NAME))
|
||||
.geolocation(set.getString(GeoInfoTable.GEOLOCATION))
|
||||
.registered(set.getLong(UsersTable.REGISTERED))
|
||||
.lastSeen(set.getLong("last_seen"))
|
||||
.sessionCount(set.getInt("count"))
|
||||
.playtime(set.getLong("playtime"))
|
||||
.activityIndex(new ActivityIndex(set.getDouble("activity_index"), date));
|
||||
if (set.getBoolean(UserInfoTable.BANNED)) {
|
||||
player.banned();
|
||||
}
|
||||
players.add(player.build());
|
||||
}
|
||||
return players;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -29,7 +29,6 @@ import com.djrapitops.plan.storage.database.queries.QueryStatement;
|
||||
import com.djrapitops.plan.storage.database.sql.parsing.Sql;
|
||||
import com.djrapitops.plan.storage.database.sql.tables.*;
|
||||
import com.djrapitops.plan.utilities.comparators.DateHolderRecentComparator;
|
||||
import com.djrapitops.plan.utilities.comparators.SessionStartComparator;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
@ -263,7 +262,7 @@ public class SessionQueries {
|
||||
.flatMap(Collection::stream)
|
||||
.map(SortedMap::values)
|
||||
.flatMap(Collection::stream)
|
||||
.sorted(new SessionStartComparator()) // Disorder arises
|
||||
.sorted(dateColderRecentComparator) // Disorder arises
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@ import com.djrapitops.plan.PlanSystem;
|
||||
import com.djrapitops.plan.data.element.TableContainer;
|
||||
import com.djrapitops.plan.delivery.domain.DateObj;
|
||||
import com.djrapitops.plan.delivery.domain.Nickname;
|
||||
import com.djrapitops.plan.delivery.domain.TablePlayer;
|
||||
import com.djrapitops.plan.delivery.domain.WebUser;
|
||||
import com.djrapitops.plan.delivery.domain.container.PlayerContainer;
|
||||
import com.djrapitops.plan.delivery.domain.container.ServerContainer;
|
||||
@ -1406,7 +1407,7 @@ public interface DatabaseTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
default void activeTunredInactiveQueryHasAllParametersSet() {
|
||||
default void activeTurnedInactiveQueryHasAllParametersSet() {
|
||||
Integer result = db().query(ActivityIndexQueries.countRegularPlayersTurnedInactive(
|
||||
0, System.currentTimeMillis(), serverUUID(),
|
||||
TimeUnit.HOURS.toMillis(2L)
|
||||
@ -1414,6 +1415,14 @@ public interface DatabaseTest {
|
||||
assertNotNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
default void serverTablePlayersQueryQueriesAtLeastOnePlayer() {
|
||||
sessionsAreStoredWithAllData();
|
||||
|
||||
List<TablePlayer> result = db().query(new ServerTablePlayersQuery(serverUUID(), System.currentTimeMillis(), 10L, 1));
|
||||
assertNotEquals(Collections.emptyList(), result);
|
||||
}
|
||||
|
||||
@PluginInfo(name = "ConditionalExtension")
|
||||
class ConditionalExtension implements DataExtension {
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user