2021-07-17 11:19:33 +02:00
/ *
* 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.webserver.resolver.json ;
2023-08-20 10:56:13 +02:00
import com.djrapitops.plan.delivery.domain.auth.WebPermission ;
2021-07-17 11:19:33 +02:00
import com.djrapitops.plan.delivery.domain.mutators.TPSMutator ;
import com.djrapitops.plan.delivery.formatting.Formatter ;
import com.djrapitops.plan.delivery.formatting.Formatters ;
2022-07-13 20:21:20 +02:00
import com.djrapitops.plan.delivery.web.resolver.MimeType ;
2021-07-17 11:19:33 +02:00
import com.djrapitops.plan.delivery.web.resolver.Resolver ;
import com.djrapitops.plan.delivery.web.resolver.Response ;
import com.djrapitops.plan.delivery.web.resolver.request.Request ;
import com.djrapitops.plan.delivery.web.resolver.request.WebUser ;
import com.djrapitops.plan.gathering.domain.TPS ;
import com.djrapitops.plan.identification.ServerUUID ;
import com.djrapitops.plan.settings.config.PlanConfig ;
import com.djrapitops.plan.settings.config.paths.DisplaySettings ;
import com.djrapitops.plan.settings.locale.Locale ;
import com.djrapitops.plan.settings.locale.lang.GenericLang ;
import com.djrapitops.plan.storage.database.DBSystem ;
import com.djrapitops.plan.storage.database.Database ;
import com.djrapitops.plan.storage.database.queries.objects.TPSQueries ;
2023-01-14 21:17:50 +01:00
import com.djrapitops.plan.utilities.dev.Untrusted ;
2021-07-17 11:19:33 +02:00
import com.google.gson.Gson ;
import com.google.gson.reflect.TypeToken ;
2022-07-13 20:21:20 +02:00
import io.swagger.v3.oas.annotations.Operation ;
import io.swagger.v3.oas.annotations.Parameter ;
import io.swagger.v3.oas.annotations.enums.ParameterIn ;
import io.swagger.v3.oas.annotations.media.Content ;
import io.swagger.v3.oas.annotations.media.ExampleObject ;
import io.swagger.v3.oas.annotations.parameters.RequestBody ;
import io.swagger.v3.oas.annotations.responses.ApiResponse ;
import jakarta.ws.rs.GET ;
import jakarta.ws.rs.Path ;
2021-07-17 11:19:33 +02:00
import javax.inject.Inject ;
import javax.inject.Singleton ;
import java.util.* ;
import java.util.concurrent.TimeUnit ;
import java.util.stream.Collectors ;
/ * *
* Creates JSON payload for / server - page Performance tab .
*
* @author AuroraLS3
* /
@Singleton
2022-07-13 20:21:20 +02:00
@Path ( " /v1/network/performanceOverview " )
2021-07-17 11:19:33 +02:00
public class NetworkPerformanceJSONResolver implements Resolver {
private final PlanConfig config ;
private final Locale locale ;
private final DBSystem dbSystem ;
private final Formatter < Double > decimals ;
private final Formatter < Long > timeAmount ;
private final Formatter < Double > percentage ;
private final Formatter < Double > byteSize ;
2021-10-09 12:17:12 +02:00
private final Gson gson ;
2021-07-17 11:19:33 +02:00
@Inject
public NetworkPerformanceJSONResolver (
PlanConfig config ,
Locale locale ,
DBSystem dbSystem ,
2021-10-09 12:17:12 +02:00
Formatters formatters ,
Gson gson
2021-07-17 11:19:33 +02:00
) {
this . config = config ;
this . locale = locale ;
this . dbSystem = dbSystem ;
decimals = formatters . decimals ( ) ;
percentage = formatters . percentage ( ) ;
timeAmount = formatters . timeAmount ( ) ;
byteSize = formatters . byteSize ( ) ;
2021-10-09 12:17:12 +02:00
this . gson = gson ;
2021-07-17 11:19:33 +02:00
}
@Override
public boolean canAccess ( Request request ) {
2023-08-20 10:56:13 +02:00
return request . getUser ( ) . orElse ( new WebUser ( " " ) ) . hasPermission ( WebPermission . PAGE_NETWORK_PERFORMANCE ) ;
2021-07-17 11:19:33 +02:00
}
2022-07-13 20:21:20 +02:00
@GET
@Operation (
description = " Get performance overview information for multiple servers " ,
responses = {
@ApiResponse ( responseCode = " 200 " , content = @Content ( mediaType = MimeType . JSON , examples = {
@ExampleObject ( " { \" numbers \" : {}} " )
} ) )
} ,
parameters = {
@Parameter ( in = ParameterIn . QUERY , name = " servers " , required = true , description = " JSON list of server uuids (URI encoded) " , example = " %5B%22a779e107-0474-4d9f-8f4d-f1efb068d32e%22%5D (is [ \" a779e107-0474-4d9f-8f4d-f1efb068d32e \" ]) " )
} ,
requestBody = @RequestBody ( content = @Content ( examples = @ExampleObject ( ) ) )
)
2021-07-17 11:19:33 +02:00
@Override
public Optional < Response > resolve ( Request request ) {
List < ServerUUID > serverUUIDs = request . getQuery ( ) . get ( " servers " )
. map ( this : : getUUIDList )
. orElse ( Collections . emptyList ( ) )
. stream ( ) . map ( ServerUUID : : from )
. collect ( Collectors . toList ( ) ) ;
return Optional . of ( Response . builder ( )
. setJSONContent ( createJSONAsMap ( serverUUIDs ) )
. build ( ) ) ;
}
2023-01-14 21:17:50 +01:00
private List < UUID > getUUIDList ( @Untrusted String jsonString ) {
2021-10-09 12:17:12 +02:00
return gson . fromJson ( jsonString , new TypeToken < List < UUID > > ( ) { } . getType ( ) ) ;
2021-07-17 11:19:33 +02:00
}
public Map < String , Object > createJSONAsMap ( Collection < ServerUUID > serverUUIDs ) {
Map < String , Object > serverOverview = new HashMap < > ( ) ;
Database db = dbSystem . getDatabase ( ) ;
long now = System . currentTimeMillis ( ) ;
long monthAgo = now - TimeUnit . DAYS . toMillis ( 30L ) ;
Map < Integer , List < TPS > > tpsData = db . query ( TPSQueries . fetchTPSDataOfServers ( monthAgo , now , serverUUIDs ) ) ;
serverOverview . put ( " numbers " , createNumbersMap ( tpsData ) ) ;
return serverOverview ;
}
private Map < String , Object > createNumbersMap ( Map < Integer , List < TPS > > tpsData ) {
long now = System . currentTimeMillis ( ) ;
long dayAgo = now - TimeUnit . DAYS . toMillis ( 1L ) ;
long weekAgo = now - TimeUnit . DAYS . toMillis ( 7L ) ;
Map < String , Object > numbers = new HashMap < > ( ) ;
List < TPS > tpsDataOfAllServers = new ArrayList < > ( ) ;
tpsData . values ( ) . forEach ( tpsDataOfAllServers : : addAll ) ;
TPSMutator tpsDataMonth = new TPSMutator ( tpsDataOfAllServers ) ;
TPSMutator tpsDataWeek = tpsDataMonth . filterDataBetween ( weekAgo , now ) ;
TPSMutator tpsDataDay = tpsDataWeek . filterDataBetween ( dayAgo , now ) ;
Map < Integer , TPSMutator > mutatorsOfServersMonth = new HashMap < > ( ) ;
Map < Integer , TPSMutator > mutatorsOfServersWeek = new HashMap < > ( ) ;
Map < Integer , TPSMutator > mutatorsOfServersDay = new HashMap < > ( ) ;
for ( Map . Entry < Integer , List < TPS > > entry : tpsData . entrySet ( ) ) {
TPSMutator mutator = new TPSMutator ( entry . getValue ( ) ) ;
mutatorsOfServersMonth . put ( entry . getKey ( ) , mutator ) ;
mutatorsOfServersWeek . put ( entry . getKey ( ) , mutator . filterDataBetween ( weekAgo , now ) ) ;
mutatorsOfServersDay . put ( entry . getKey ( ) , mutator . filterDataBetween ( dayAgo , now ) ) ;
}
2021-10-11 18:39:21 +02:00
Double tpsThreshold = config . get ( DisplaySettings . GRAPH_TPS_THRESHOLD_MED ) ;
2021-07-17 11:19:33 +02:00
numbers . put ( " low_tps_spikes_30d " , tpsDataMonth . lowTpsSpikeCount ( tpsThreshold ) ) ;
numbers . put ( " low_tps_spikes_7d " , tpsDataWeek . lowTpsSpikeCount ( tpsThreshold ) ) ;
numbers . put ( " low_tps_spikes_24h " , tpsDataDay . lowTpsSpikeCount ( tpsThreshold ) ) ;
long downtimeMonth = getTotalDowntime ( mutatorsOfServersMonth ) ;
long downtimeWeek = getTotalDowntime ( mutatorsOfServersWeek ) ;
long downtimeDay = getTotalDowntime ( mutatorsOfServersDay ) ;
numbers . put ( " server_downtime_30d " , timeAmount . apply ( downtimeMonth ) ) ;
numbers . put ( " server_downtime_7d " , timeAmount . apply ( downtimeWeek ) ) ;
numbers . put ( " server_downtime_24h " , timeAmount . apply ( downtimeDay ) ) ;
if ( ! tpsData . isEmpty ( ) ) {
numbers . put ( " avg_server_downtime_30d " , timeAmount . apply ( downtimeMonth / tpsData . size ( ) ) ) ;
numbers . put ( " avg_server_downtime_7d " , timeAmount . apply ( downtimeWeek / tpsData . size ( ) ) ) ;
numbers . put ( " avg_server_downtime_24h " , timeAmount . apply ( downtimeDay / tpsData . size ( ) ) ) ;
} else {
numbers . put ( " avg_server_downtime_30d " , " - " ) ;
numbers . put ( " avg_server_downtime_7d " , " - " ) ;
numbers . put ( " avg_server_downtime_24h " , " - " ) ;
}
2022-09-11 18:30:57 +02:00
numbers . put ( " players_30d " , format ( tpsDataMonth . averagePlayers ( ) ) ) ;
numbers . put ( " players_7d " , format ( tpsDataWeek . averagePlayers ( ) ) ) ;
numbers . put ( " players_24h " , format ( tpsDataDay . averagePlayers ( ) ) ) ;
2021-07-17 11:19:33 +02:00
numbers . put ( " tps_30d " , format ( tpsDataMonth . averageTPS ( ) ) ) ;
numbers . put ( " tps_7d " , format ( tpsDataWeek . averageTPS ( ) ) ) ;
numbers . put ( " tps_24h " , format ( tpsDataDay . averageTPS ( ) ) ) ;
numbers . put ( " cpu_30d " , formatPercentage ( tpsDataMonth . averageCPU ( ) ) ) ;
numbers . put ( " cpu_7d " , formatPercentage ( tpsDataWeek . averageCPU ( ) ) ) ;
numbers . put ( " cpu_24h " , formatPercentage ( tpsDataDay . averageCPU ( ) ) ) ;
numbers . put ( " ram_30d " , formatBytes ( tpsDataMonth . averageRAM ( ) ) ) ;
numbers . put ( " ram_7d " , formatBytes ( tpsDataWeek . averageRAM ( ) ) ) ;
numbers . put ( " ram_24h " , formatBytes ( tpsDataDay . averageRAM ( ) ) ) ;
numbers . put ( " entities_30d " , format ( ( int ) tpsDataMonth . averageEntities ( ) ) ) ;
numbers . put ( " entities_7d " , format ( ( int ) tpsDataWeek . averageEntities ( ) ) ) ;
numbers . put ( " entities_24h " , format ( ( int ) tpsDataDay . averageEntities ( ) ) ) ;
numbers . put ( " chunks_30d " , format ( ( int ) tpsDataMonth . averageChunks ( ) ) ) ;
numbers . put ( " chunks_7d " , format ( ( int ) tpsDataWeek . averageChunks ( ) ) ) ;
numbers . put ( " chunks_24h " , format ( ( int ) tpsDataDay . averageChunks ( ) ) ) ;
return numbers ;
}
private long getTotalDowntime ( Map < Integer , TPSMutator > mutatorsOfServersMonth ) {
long downTime = 0L ;
for ( TPSMutator tpsMutator : mutatorsOfServersMonth . values ( ) ) {
downTime + = tpsMutator . serverDownTime ( ) ;
}
return downTime ;
}
private String format ( double value ) {
return value ! = - 1 ? decimals . apply ( value ) : locale . get ( GenericLang . UNAVAILABLE ) . toString ( ) ;
}
private String formatBytes ( double value ) {
return value ! = - 1 ? byteSize . apply ( value ) : locale . get ( GenericLang . UNAVAILABLE ) . toString ( ) ;
}
private String formatPercentage ( double value ) {
return value ! = - 1 ? percentage . apply ( value / 100 . 0 ) : locale . get ( GenericLang . UNAVAILABLE ) . toString ( ) ;
}
}