Skip to content

Commit b03864b

Browse files
committed
Add AVERAGE_TPS datapoint
1 parent da52434 commit b03864b

9 files changed

Lines changed: 154 additions & 35 deletions

File tree

Plan/common/src/main/java/com/djrapitops/plan/delivery/domain/auth/WebPermission.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ public enum WebPermission implements Supplier<String>, Lang {
171171
DATA_PLAYER_DEATHS("See Deaths datapoint of players"),
172172
DATA_SERVER_DEATHS("See Deaths datapoint of servers"),
173173
DATA_NETWORK_DEATHS("See Deaths datapoint of network"),
174+
DATA_SERVER_AVERAGE_TPS("See Average TPS datapoint of servers"),
174175

175176
ACCESS("Controls access to pages"),
176177
ACCESS_PLAYER("Allows accessing any /player pages"),

Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/json/datapoint/Datapoint.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,6 @@ enum FormatType {
4343
PERCENTAGE,
4444
BYTES,
4545
SPECIAL,
46-
NONE
46+
DECIMAL, NONE
4747
}
4848
}

Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/json/datapoint/DatapointType.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ public enum DatapointType {
4848
CURRENT_UPTIME(CurrentUptime.class),
4949
MOB_KILLS(MobKills.class, DatapointCacheKey.SESSION),
5050
PLAYER_KILLS(PlayerKills.class, DatapointCacheKey.SESSION),
51-
DEATHS(Deaths.class, DatapointCacheKey.SESSION);
51+
DEATHS(Deaths.class, DatapointCacheKey.SESSION),
52+
AVERAGE_TPS(AverageTPS.class, DatapointCacheKey.TPS);
5253

5354
private final Class<? extends Datapoint<?>> datapointClass;
5455
private final DatapointCacheKey[] cacheKeys;
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* This file is part of Player Analytics (Plan).
3+
*
4+
* Plan is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU Lesser General Public License v3 as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* Plan is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU Lesser General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU Lesser General Public License
15+
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
16+
*/
17+
package com.djrapitops.plan.delivery.rendering.json.datapoint.types;
18+
19+
import com.djrapitops.plan.delivery.domain.auth.WebPermission;
20+
import com.djrapitops.plan.delivery.domain.datatransfer.GenericFilter;
21+
import com.djrapitops.plan.delivery.rendering.json.datapoint.Datapoint;
22+
import com.djrapitops.plan.delivery.rendering.json.datapoint.DatapointType;
23+
import com.djrapitops.plan.delivery.web.resolver.exception.BadRequestException;
24+
import com.djrapitops.plan.storage.database.DBSystem;
25+
import com.djrapitops.plan.storage.database.queries.objects.TPSQueries;
26+
27+
import javax.inject.Inject;
28+
import javax.inject.Singleton;
29+
import java.util.Optional;
30+
31+
/**
32+
* Datapoint for looking up Average TPS within the timeframe.
33+
*
34+
* @author AuroraLS3
35+
*/
36+
@Singleton
37+
public class AverageTPS implements Datapoint<Double> {
38+
39+
private final DBSystem dbSystem;
40+
41+
@Inject
42+
public AverageTPS(DBSystem dbSystem) {
43+
this.dbSystem = dbSystem;
44+
}
45+
46+
@Override
47+
public Optional<Double> getValue(GenericFilter filter) {
48+
if (filter.getPlayerUUID().isPresent()) {
49+
throw new BadRequestException("AVERAGE_TPS does not support player parameter");
50+
}
51+
52+
if (filter.getServerUUIDs().isEmpty()) {
53+
throw new BadRequestException("AVERAGE_TPS is only available for servers");
54+
}
55+
56+
double average = dbSystem.getDatabase().query(TPSQueries.averageTPS(filter.getAfter(), filter.getBefore(), filter.getServerUUIDs()));
57+
return average != -1.0 ? Optional.of(average) : Optional.empty();
58+
}
59+
60+
@Override
61+
public WebPermission getPermission(GenericFilter filter) {
62+
if (filter.getPlayerUUID().isPresent()) {
63+
return WebPermission.DATA_PLAYER;
64+
} else if (!filter.getServerUUIDs().isEmpty()) {
65+
return WebPermission.DATA_SERVER_AVERAGE_TPS;
66+
} else {
67+
return WebPermission.DATA_NETWORK;
68+
}
69+
}
70+
71+
@Override
72+
public DatapointType getType() {
73+
return DatapointType.AVERAGE_TPS;
74+
}
75+
76+
@Override
77+
public FormatType getFormatType() {
78+
return FormatType.DECIMAL;
79+
}
80+
}

Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/json/datapoint/types/DatapointModule.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,4 +107,8 @@ public interface DatapointModule {
107107
@Binds
108108
@IntoSet
109109
Datapoint<?> bindPlayerKills(PlayerKills playerKills);
110+
111+
@Binds
112+
@IntoSet
113+
Datapoint<?> bindAverageTPS(AverageTPS averageTPS);
110114
}

Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/TPSQueries.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -425,18 +425,25 @@ public Optional<TPS> processResults(ResultSet set) throws SQLException {
425425
}
426426

427427
public static Query<Double> averageTPS(long after, long before, ServerUUID serverUUID) {
428+
return averageTPS(after, before, Collections.singletonList(serverUUID));
429+
}
430+
431+
public static Query<Double> averageTPS(long after, long before, List<ServerUUID> serverUUIDs) {
432+
if (serverUUIDs.isEmpty()) {
433+
return db -> -1.0;
434+
}
435+
428436
String sql = SELECT + "AVG(" + TPS + ") as average" + FROM + TABLE_NAME + " t" +
429437
INNER_JOIN + ServerTable.TABLE_NAME + " s ON s." + ServerTable.ID + "=t." + SERVER_ID +
430-
WHERE + "s." + ServerTable.SERVER_UUID + "=?" +
438+
WHERE + "s." + ServerTable.SERVER_UUID + " IN (" + ServerTable.uuids(serverUUIDs) + ")" +
431439
AND + TPS + ">=0" +
432440
AND + DATE + "<?" +
433441
AND + DATE + ">?";
434442
return new QueryStatement<>(sql) {
435443
@Override
436444
public void prepare(PreparedStatement statement) throws SQLException {
437-
statement.setString(1, serverUUID.toString());
438-
statement.setLong(2, before);
439-
statement.setLong(3, after);
445+
statement.setLong(1, before);
446+
statement.setLong(2, after);
440447
}
441448

442449
@Override

Plan/common/src/test/java/com/djrapitops/plan/delivery/webserver/AccessControlTest.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,10 @@ static Stream<Arguments> testCases() {
236236
Arguments.of("/v1/datapoint?type=PLAYER_KILLS&player=" + TestConstants.PLAYER_ONE_UUID_STRING, WebPermission.DATA_PLAYER_PLAYER_KILLS, 200, 403),
237237
Arguments.of("/v1/datapoint?type=MOB_KILLS", WebPermission.DATA_NETWORK_MOB_KILLS, 200, 403),
238238
Arguments.of("/v1/datapoint?type=MOB_KILLS&server=" + TestConstants.SERVER_UUID_STRING, WebPermission.DATA_SERVER_MOB_KILLS, 200, 403),
239-
Arguments.of("/v1/datapoint?type=MOB_KILLS&player=" + TestConstants.PLAYER_ONE_UUID_STRING, WebPermission.DATA_PLAYER_MOB_KILLS, 200, 403)
239+
Arguments.of("/v1/datapoint?type=MOB_KILLS&player=" + TestConstants.PLAYER_ONE_UUID_STRING, WebPermission.DATA_PLAYER_MOB_KILLS, 200, 403),
240+
Arguments.of("/v1/datapoint?type=AVERAGE_TPS", WebPermission.DATA_SERVER_AVERAGE_TPS, 400, 403),
241+
Arguments.of("/v1/datapoint?type=AVERAGE_TPS&server=" + TestConstants.SERVER_UUID_STRING, WebPermission.DATA_SERVER_AVERAGE_TPS, 200, 403),
242+
Arguments.of("/v1/datapoint?type=AVERAGE_TPS&player=" + TestConstants.PLAYER_ONE_UUID_STRING, WebPermission.DATA_SERVER_AVERAGE_TPS, 400, 403)
240243
);
241244
}
242245

Plan/react/dashboard/src/dataHooks/model/datapoint/Datapoint.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,15 @@ import {baseAddress, staticSite} from "../../../service/backendConfiguration";
66
import {filterToQueryString, GenericFilter} from "../GenericFilter";
77
import {MS_24H, MS_WEEK} from "../../../util/format/useDateFormatter";
88

9-
export type FormatType = 'NONE' | 'TIME_AMOUNT' | 'TIME_SINCE' | 'DATE' | 'PERCENTAGE' | 'BYTES' | 'SPECIAL';
9+
export type FormatType =
10+
'NONE'
11+
| 'TIME_AMOUNT'
12+
| 'TIME_SINCE'
13+
| 'DATE'
14+
| 'DECIMAL'
15+
| 'PERCENTAGE'
16+
| 'BYTES'
17+
| 'SPECIAL';
1018

1119
export enum DatapointType {
1220
WORLD_PIE = 'WORLD_PIE',
@@ -29,6 +37,7 @@ export enum DatapointType {
2937
DEATHS = "DEATHS",
3038
PLAYER_KILLS = "PLAYER_KILLS",
3139
MOB_KILLS = "MOB_KILLS",
40+
AVERAGE_TPS = "AVERAGE_TPS",
3241
}
3342

3443
export type DatapointTypeMap = {
@@ -47,6 +56,7 @@ export type DatapointTypeMap = {
4756
DEATHS: number;
4857
PLAYER_KILLS: number;
4958
MOB_KILLS: number;
59+
AVERAGE_TPS: number;
5060
SERVER_OCCUPIED: OutOf;
5161
MOST_ACTIVE_WORLD: OutOfCategory;
5262
MOST_ACTIVE_GAME_MODE: OutOfCategory;

Plan/react/dashboard/src/views/server/ServerOverview.jsx

Lines changed: 40 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,20 @@ import ExtendableRow from "../../components/layout/extension/ExtendableRow";
2525
import {useAuth} from "../../hooks/authenticationHook.tsx";
2626
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
2727
import FormattedTime from "../../components/text/FormattedTime.jsx";
28+
import {QueryDatapoint, useDatapointQuery} from "../../components/datapoint/QueryDatapoint.tsx";
29+
import {DatapointType} from "../../dataHooks/model/datapoint/Datapoint.ts";
30+
import {MS_WEEK} from "../../util/format/useDateFormatter.js";
31+
import {GenericFilterContextProvider} from "../../dataHooks/genericFilterContextHook.tsx";
2832

2933
const Last7DaysCard = ({data}) => {
3034
const {t} = useTranslation();
35+
const {identifier} = useParams();
3136

32-
if (!data) return <CardLoader/>;
3337

34-
const noData = data.average_tps === 'plugin.generic.unavailable'
38+
const {error} = useDatapointQuery(true, DatapointType.AVERAGE_TPS, {server: identifier, afterMillisAgo: MS_WEEK})
39+
const noData = error?.status === 404
3540

41+
if (!data) return <CardLoader/>;
3642
return (
3743
<Card id={"last-7-days"}>
3844
<Card.Header>
@@ -43,31 +49,38 @@ const Last7DaysCard = ({data}) => {
4349
{noData && <Alert className='alert-warning mb-0'>
4450
<FontAwesomeIcon icon={faInfoCircle}/> {t('html.description.noData7d')}
4551
</Alert>}
46-
<Card.Body>
47-
<Datapoint name={t('html.label.uniquePlayers')}
48-
color={'players-unique'} icon={faUsers}
49-
value={data.unique_players} bold/>
50-
<Datapoint name={t('html.label.uniquePlayers') + ' ' + t('html.label.perDay')}
51-
color={'players-unique'} icon={faUser}
52-
value={data.unique_players_day} bold/>
53-
<Datapoint name={t('html.label.newPlayers')}
54-
color={'players-new'} icon={faUsers}
55-
value={data.new_players} bold/>
56-
<Datapoint name={t('html.label.newPlayerRetention')}
57-
color={'players-new'} icon={faUserCircle}
58-
value={data.new_players_retention_perc}
59-
valueLabel={data.new_players_retention + '/' + data.new_players} bold/>
60-
<hr/>
61-
<Datapoint name={t('html.label.averageTps')}
62-
color={'tps-average'} icon={faTachometerAlt}
63-
value={data.average_tps} bold/>
64-
<Datapoint name={t('html.label.lowTpsSpikes')}
65-
color={'tps-low-spikes'} icon={faExclamationCircle}
66-
value={data.low_tps_spikes} bold/>
67-
<Datapoint name={t('html.label.downtime')}
68-
color={'downtime'} icon={faPowerOff}
69-
value={<FormattedTime timeMs={data.downtime}/>}/>
70-
</Card.Body>
52+
<GenericFilterContextProvider initialValue={{server: identifier, afterMillisAgo: MS_WEEK}}>
53+
{filter => (
54+
<Card.Body>
55+
<QueryDatapoint name={t('html.label.uniquePlayers')}
56+
color={'players-unique'} icon={faUsers}
57+
dataType={DatapointType.UNIQUE_PLAYERS}
58+
filter={filter} bold/>
59+
<Datapoint name={t('html.label.uniquePlayers') + ' ' + t('html.label.perDay')}
60+
color={'players-unique'} icon={faUser}
61+
value={data.unique_players_day} bold/>
62+
<QueryDatapoint name={t('html.label.newPlayers')}
63+
color={'players-new'} icon={faUsers}
64+
dataType={DatapointType.NEW_PLAYERS}
65+
filter={filter} bold/>
66+
<Datapoint name={t('html.label.newPlayerRetention')}
67+
color={'players-new'} icon={faUserCircle}
68+
value={data.new_players_retention_perc}
69+
valueLabel={data.new_players_retention + '/' + data.new_players} bold/>
70+
<hr/>
71+
<QueryDatapoint name={t('html.label.averageTps')}
72+
color={'tps-average'} icon={faTachometerAlt}
73+
dataType={DatapointType.AVERAGE_TPS}
74+
filter={filter} bold/>
75+
<Datapoint name={t('html.label.lowTpsSpikes')}
76+
color={'tps-low-spikes'} icon={faExclamationCircle}
77+
value={data.low_tps_spikes} bold/>
78+
<Datapoint name={t('html.label.downtime')}
79+
color={'downtime'} icon={faPowerOff}
80+
value={<FormattedTime timeMs={data.downtime}/>}/>
81+
</Card.Body>
82+
)}
83+
</GenericFilterContextProvider>
7184
</Card>
7285
)
7386
}

0 commit comments

Comments
 (0)